From 4c2933b38d36dca8e2e0a2d412114a1bd1ab0d92 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 17 May 2021 18:44:32 -0400 Subject: [PATCH 001/153] Adding gems metadata query --- cmake/Tools/registration.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/cmake/Tools/registration.py b/cmake/Tools/registration.py index 184d2cdb31..70fbc5ba90 100755 --- a/cmake/Tools/registration.py +++ b/cmake/Tools/registration.py @@ -2216,6 +2216,19 @@ def get_gem_data(gem_name: str = None, return None +def get_gems_metadata(): + gem_list = get_gems() + get_engine_gems() + gem_data_dict = {} + for gem in gem_list: + json_path = os.path.join(gem, 'gem.json') + if (os.path.exists(json_path)): + with open(json_path, 'r') as gem_json: + parsed_meta_data = json.loads(gem_json.read()) + gem_data_dict[str(parsed_meta_data['gem_name'])] = parsed_meta_data + else: + logger.error(f'Gem json {gem_json} is not present.') + json_result = json.dumps(gem_data_dict, indent = 4) + return json_result def get_template_data(template_name: str = None, template_path: str or pathlib.Path = None, ) -> dict or None: @@ -2410,6 +2423,12 @@ def print_downloadables(verbose: int) -> None: print_templates_data(downloadable_data['templates']) print_restricted_data(downloadable_data['templates']) +def print_gems_metadata(verbose: int) -> None: + gems_data = get_gems_metadata() + print(gems_data) + if verbose > 0: + gem_list = get_gems() + get_engine_gems() + print(gem_list) def download_engine(engine_name: str, dest_path: str) -> int: @@ -3833,7 +3852,6 @@ def _run_register_show(args: argparse) -> int: if args.this_engine: print_this_engine(args.verbose) return 0 - elif args.engines: print_engines(args.verbose) return 0 @@ -3897,6 +3915,9 @@ def _run_register_show(args: argparse) -> int: elif args.downloadable_templates: print_downloadable_templates(args.verbose) return 0 + elif args.gems_data: + print_gems_metadata(args.verbose) + return 0 else: register_show(args.verbose) return 0 @@ -4168,6 +4189,9 @@ def add_args(parser, subparsers) -> None: group.add_argument('-dt', '--downloadable-templates', action='store_true', required=False, default=False, help='Combine all repos templates into a single list of resources.') + group.add_argument('-gd', '--gems-data', action='store_true', required=False, + default=False, + help='Returns a json formatted string of meta data for all local and engine gems.') register_show_subparser.add_argument('-v', '--verbose', action='count', required=False, default=0, From 17e9c17f311bca70b61b3295c4aef49d23a2dd46 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 26 May 2021 19:18:18 -0700 Subject: [PATCH 002/153] Added Occlusion Culling Planes and RPI Culling support for Masked Occlusion Culling --- ...ionCullingPlaneFeatureProcessorInterface.h | 41 +++++ .../Code/Source/CommonSystemComponent.cpp | 4 + .../OcclusionCullingPlaneFeatureProcessor.cpp | 96 ++++++++++ .../OcclusionCullingPlaneFeatureProcessor.h | 75 ++++++++ .../Code/atom_feature_common_files.cmake | 2 + .../atom_feature_common_public_files.cmake | 1 + .../Code/Include/Atom/RPI.Public/Culling.h | 12 +- .../RPI/Code/Include/Atom/RPI.Public/View.h | 12 +- .../Source/Platform/Windows/PAL_windows.cmake | 13 ++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 171 +++++++++++++----- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 3 +- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 68 ++++++- .../Atom/RPI/Code/atom_rpi_public_files.cmake | 4 + .../CommonFeatures/Code/Source/Module.cpp | 4 + .../EditorOcclusionCullingPlaneComponent.cpp | 91 ++++++++++ .../EditorOcclusionCullingPlaneComponent.h | 43 +++++ .../OcclusionCullingPlaneComponent.cpp | 43 +++++ .../OcclusionCullingPlaneComponent.h | 37 ++++ .../OcclusionCullingPlaneComponentConstants.h | 22 +++ ...clusionCullingPlaneComponentController.cpp | 137 ++++++++++++++ ...OcclusionCullingPlaneComponentController.h | 78 ++++++++ ...egration_commonfeatures_editor_files.cmake | 2 + ...omlyintegration_commonfeatures_files.cmake | 4 + 23 files changed, 913 insertions(+), 50 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h new file mode 100644 index 0000000000..07a6179e78 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h @@ -0,0 +1,41 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class OcclusionCullingPlane; + + using OcclusionCullingPlaneHandle = AZStd::shared_ptr; + + // OcclusionCullingPlaneFeatureProcessorInterface provides an interface to the feature processor for code outside of Atom + class OcclusionCullingPlaneFeatureProcessorInterface + : public RPI::FeatureProcessor + { + public: + AZ_RTTI(AZ::Render::OcclusionCullingPlaneFeatureProcessorInterface, "{50F6B45E-A622-44EC-B962-DE25FBD44095}"); + + virtual OcclusionCullingPlaneHandle AddOcclusionCullingPlane(const AZ::Transform& transform) = 0; + virtual void RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& handle) = 0; + virtual bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const = 0; + virtual void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) = 0; + virtual void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled) = 0; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 089a6168b1..614e614c06 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -102,6 +102,7 @@ #include #include #include +#include namespace AZ { @@ -137,6 +138,7 @@ namespace AZ ModelPreset::Reflect(context); DiffuseProbeGridFeatureProcessor::Reflect(context); RayTracingFeatureProcessor::Reflect(context); + OcclusionCullingPlaneFeatureProcessor::Reflect(context); if (SerializeContext* serialize = azrtti_cast(context)) { @@ -193,6 +195,7 @@ namespace AZ AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); + AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); // Add SkyBox pass auto* passSystem = RPI::PassSystemInterface::Get(); @@ -295,6 +298,7 @@ namespace AZ AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); + AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); } void CommonSystemComponent::LoadPassTemplateMappings() diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp new file mode 100644 index 0000000000..d4a1a37521 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp @@ -0,0 +1,96 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + void OcclusionCullingPlaneFeatureProcessor::Reflect(ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext + ->Class() + ->Version(0); + } + } + + void OcclusionCullingPlaneFeatureProcessor::Activate() + { + m_occlusionCullingPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize); + + EnableSceneNotification(); + } + + void OcclusionCullingPlaneFeatureProcessor::Deactivate() + { + AZ_Warning("OcclusionCullingPlaneFeatureProcessor", m_occlusionCullingPlanes.size() == 0, + "Deactivating the OcclusionCullingPlaneFeatureProcessor, but there are still outstanding occlusion planes. Components\n" + "using OcclusionCullingPlaneHandles should free them before the OcclusionCullingPlaneFeatureProcessor is deactivated.\n" + ); + + DisableSceneNotification(); + } + + void OcclusionCullingPlaneFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet) + { + AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); + + AZStd::vector occlusionCullingPlanes; + for (auto& occlusionCullingPlane : m_occlusionCullingPlanes) + { + occlusionCullingPlanes.push_back(occlusionCullingPlane->GetTransform()); + } + GetParentScene()->GetCullingScene()->SetOcclusionCullingPlanes(occlusionCullingPlanes); + } + + OcclusionCullingPlaneHandle OcclusionCullingPlaneFeatureProcessor::AddOcclusionCullingPlane(const AZ::Transform& transform) + { + AZStd::shared_ptr occlusionCullingPlane = AZStd::make_shared(); + occlusionCullingPlane->SetTransform(transform); + m_occlusionCullingPlanes.push_back(occlusionCullingPlane); + return occlusionCullingPlane; + } + + void OcclusionCullingPlaneFeatureProcessor::RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& occlusionCullingPlane) + { + AZ_Assert(occlusionCullingPlane.get(), "RemoveOcclusionCullingPlane called with an invalid handle"); + + auto itEntry = AZStd::find_if(m_occlusionCullingPlanes.begin(), m_occlusionCullingPlanes.end(), [&](AZStd::shared_ptr const& entry) + { + return (entry == occlusionCullingPlane); + }); + + AZ_Assert(itEntry != m_occlusionCullingPlanes.end(), "RemoveOcclusionCullingPlane called with an occlusion plane that is not in the occlusion plane list"); + m_occlusionCullingPlanes.erase(itEntry); + occlusionCullingPlane = nullptr; + } + + void OcclusionCullingPlaneFeatureProcessor::SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) + { + AZ_Assert(occlusionCullingPlane.get(), "SetTransform called with an invalid handle"); + occlusionCullingPlane->SetTransform(transform); + } + + void OcclusionCullingPlaneFeatureProcessor::SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled) + { + AZ_Assert(occlusionCullingPlane.get(), "Enable called with an invalid handle"); + occlusionCullingPlane->SetEnabled(enabled); + } + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h new file mode 100644 index 0000000000..c54c816bfd --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h @@ -0,0 +1,75 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include + +namespace AZ +{ + namespace Render + { + //! This class represents an OcclusionCullingPlane which is used to cull meshes that are inside the view frustum + class OcclusionCullingPlane final + { + public: + OcclusionCullingPlane() = default; + ~OcclusionCullingPlane() = default; + + void SetTransform(const AZ::Transform& transform) { m_transform = transform; } + const AZ::Transform& GetTransform() const { return m_transform; } + + void SetEnabled(bool enabled) { m_enabled = enabled; } + bool GetEnabled() const { return m_enabled; } + + private: + AZ::Transform m_transform; + bool m_enabled = true; + }; + + //! This class manages OcclusionCullingPlanes which are used to cull meshes that are inside the view frustum + class OcclusionCullingPlaneFeatureProcessor final + : public OcclusionCullingPlaneFeatureProcessorInterface + { + public: + AZ_RTTI(AZ::Render::OcclusionCullingPlaneFeatureProcessor, "{C3DE91D7-EF7A-4A82-A55F-E22BC52074EA}", OcclusionCullingPlaneFeatureProcessorInterface); + + static void Reflect(AZ::ReflectContext* context); + + OcclusionCullingPlaneFeatureProcessor() = default; + virtual ~OcclusionCullingPlaneFeatureProcessor() = default; + + // OcclusionCullingPlaneFeatureProcessorInterface overrides + OcclusionCullingPlaneHandle AddOcclusionCullingPlane(const AZ::Transform& transform) override; + void RemoveOcclusionCullingPlane(OcclusionCullingPlaneHandle& handle) override; + bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const override { return (occlusionCullingPlane.get() != nullptr); } + void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) override; + void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enable) override; + + // FeatureProcessor overrides + void Activate() override; + void Deactivate() override; + void Simulate(const FeatureProcessor::SimulatePacket& packet) override; + + // retrieve the full list of occlusion planes + using OcclusionCullingPlaneVector = AZStd::vector>; + OcclusionCullingPlaneVector& GetOcclusionCullingPlanes() { return m_occlusionCullingPlanes; } + + private: + AZ_DISABLE_COPY_MOVE(OcclusionCullingPlaneFeatureProcessor); + + // list of occlusion planes + const size_t InitialOcclusionCullingPlanesAllocationSize = 64; + OcclusionCullingPlaneVector m_occlusionCullingPlanes; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 8926b0c19f..f3ee1b4757 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -175,6 +175,8 @@ set(FILES Source/MorphTargets/MorphTargetComputePass.h Source/MorphTargets/MorphTargetDispatchItem.cpp Source/MorphTargets/MorphTargetDispatchItem.h + Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h + Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp Source/PostProcess/PostProcessBase.cpp Source/PostProcess/PostProcessBase.h Source/PostProcess/PostProcessFeatureProcessor.cpp diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake index 9034859707..3df15f9a70 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake @@ -44,6 +44,7 @@ set(FILES Include/Atom/Feature/ParamMacros/StartParamFunctionsVirtual.inl Include/Atom/Feature/ParamMacros/StartParamMembers.inl Include/Atom/Feature/ParamMacros/StartParamSerializeContext.inl + Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h Include/Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h Include/Atom/Feature/PostProcess/PostProcessParams.inl Include/Atom/Feature/PostProcess/PostProcessSettings.inl 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 c7e9cc4706..17e0a1f82d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -31,7 +31,7 @@ #include #include - +#include #include #include @@ -213,8 +213,11 @@ namespace AZ void Activate(const class Scene* parentScene); void Deactivate(); + //! Sets a list of occlusion planes to be used during the culling process. + void SetOcclusionCullingPlanes(const AZStd::vector& occlusionCullingPlanes) { m_occlusionCullingPlanes = occlusionCullingPlanes; } + //! Notifies the CullingScene that culling will begin for this frame. - void BeginCulling(const AZStd::vector& views); + void BeginCulling(const AZStd::vector& views, const AZStd::vector& activePipelines); //! Notifies the CullingScene that the culling is done for this frame. void EndCulling(); @@ -251,12 +254,9 @@ namespace AZ const Scene* m_parentScene = nullptr; AzFramework::IVisibilityScene* m_visScene = nullptr; - CullingDebugContext m_debugCtx; - AZStd::concurrency_checker m_cullDataConcurrencyCheck; - - AZStd::mutex m_mutex; + AZStd::vector m_occlusionCullingPlanes; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index aad099dc23..74c841d2a5 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,7 @@ namespace AZ //! Only use this function to create a new view object. And force using smart pointer to manage view's life time static ViewPtr CreateView(const AZ::Name& name, UsageFlags usage); - ~View() = default; + ~View(); void SetDrawListMask(const RHI::DrawListMask& drawListMask); RHI::DrawListMask GetDrawListMask() const { return m_drawListMask; } @@ -126,6 +127,12 @@ namespace AZ //! Notifies consumers when the world to clip matrix has changed. void ConnectWorldToClipMatrixChangedHandler(MatrixChangedEvent::Handler& handler); + //! Prepare for view culling + void BeginCulling(const AZStd::vector& activePipelines); + + //! Returns the masked occlusion culling interface + MaskedOcclusionCulling* GetMaskedOcclusionCulling(); + private: View() = delete; View(const AZ::Name& name, UsageFlags usage); @@ -193,6 +200,9 @@ namespace AZ MatrixChangedEvent m_onWorldToClipMatrixChange; MatrixChangedEvent m_onWorldToViewMatrixChange; + + // Software occlusion culling + MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; }; AZ_DEFINE_ENUM_BITWISE_OPERATORS(View::UsageFlags); diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake b/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake index c060b8bbaa..51e42d5216 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake @@ -10,3 +10,16 @@ # set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED TRUE) + +ly_add_source_properties( + SOURCES Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp + PROPERTY COMPILE_OPTIONS + VALUES /arch:AVX2 /W3 +) +ly_add_source_properties( + SOURCES + Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp + Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp + PROPERTY COMPILE_OPTIONS + VALUES /W3 +) \ No newline at end of file diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index c64f08e4f8..ab25fb14fb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -262,21 +262,24 @@ namespace AZ public: AZ_CLASS_ALLOCATOR(AddObjectsToViewJob, ThreadPoolAllocator, 0); + struct JobData + { + CullingDebugContext* m_debugCtx = nullptr; + MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; + const Scene* m_scene = nullptr; + View* m_view = nullptr; + Frustum m_frustum; + }; + private: - CullingDebugContext* m_debugCtx; - const Scene* m_scene; - View* m_view; - Frustum m_frustum; + const AZStd::shared_ptr m_jobData; CullingScene::WorkListType m_worklist; public: - AddObjectsToViewJob(CullingDebugContext& debugCtx, const Scene& scene, View& view, Frustum& frustum, CullingScene::WorkListType& worklist) + AddObjectsToViewJob(const AZStd::shared_ptr& jobData, CullingScene::WorkListType& worklist) : Job(true, nullptr) //auto-deletes, no JobContext - , m_debugCtx(&debugCtx) - , m_scene(&scene) - , m_view(&view) - , m_frustum(frustum) //capture by value - , m_worklist(AZStd::move(worklist)) //capture by value + , m_jobData(jobData) + , m_worklist(worklist) { } @@ -285,37 +288,40 @@ namespace AZ { AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); - const View::UsageFlags viewFlags = m_view->GetUsageFlags(); - const RHI::DrawListMask drawListMask = m_view->GetDrawListMask(); + const View::UsageFlags viewFlags = m_jobData->m_view->GetUsageFlags(); + const RHI::DrawListMask drawListMask = m_jobData->m_view->GetDrawListMask(); uint32_t numDrawPackets = 0; uint32_t numVisibleCullables = 0; for (const AzFramework::IVisibilityScene::NodeData& nodeData : m_worklist) { //If a node is entirely contained within the frustum, then we can skip the fine grained culling. - bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_frustum, nodeData.m_bounds); + bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_jobData->m_frustum, nodeData.m_bounds); #ifdef AZ_CULL_PROFILE_VERBOSE AZ_PROFILE_SCOPE_DYNAMIC(Debug::ProfileCategory::AzRender, "process node (view: %s, skip fine cull: %d", m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0); #endif - if (nodeIsContainedInFrustum || !m_debugCtx->m_enableFrustumCulling) + if (nodeIsContainedInFrustum || !m_jobData->m_debugCtx->m_enableFrustumCulling) { //Add all objects within this node to the view, without any extra culling for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { - if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) + if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) { - Cullable* c = static_cast(visibleEntry->m_userData); - if ((c->m_cullData.m_drawListMask & drawListMask).none() || - c->m_cullData.m_hideFlags & viewFlags || - c->m_cullData.m_scene != m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this + if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { - continue; + Cullable* c = static_cast(visibleEntry->m_userData); + if ((c->m_cullData.m_drawListMask & drawListMask).none() || + c->m_cullData.m_hideFlags & viewFlags || + c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this + { + continue; + } + numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); + ++numVisibleCullables; } - numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_view); - ++numVisibleCullables; } } } @@ -329,66 +335,69 @@ namespace AZ Cullable* c = static_cast(visibleEntry->m_userData); if ((c->m_cullData.m_drawListMask & drawListMask).none() || c->m_cullData.m_hideFlags & viewFlags || - c->m_cullData.m_scene != m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this + c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this { continue; } - IntersectResult res = ShapeIntersection::Classify(m_frustum, c->m_cullData.m_boundingSphere); + IntersectResult res = ShapeIntersection::Classify(m_jobData->m_frustum, c->m_cullData.m_boundingSphere); if (res == IntersectResult::Exterior) { continue; } - else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_frustum, c->m_cullData.m_boundingObb)) + else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_jobData->m_frustum, c->m_cullData.m_boundingObb)) { - numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_view); - ++numVisibleCullables; + if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) + { + numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); + ++numVisibleCullables; + } } } } } - if (m_debugCtx->m_debugDraw && (m_view->GetName() == m_debugCtx->m_currentViewSelectionName)) + if (m_jobData->m_debugCtx->m_debugDraw && (m_jobData->m_view->GetName() == m_jobData->m_debugCtx->m_currentViewSelectionName)) { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "debug draw culling"); - AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_scene); + AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_jobData->m_scene); if (auxGeomPtr) { //Draw the node bounds // "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum. // Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so // we have a few debug booleans to toggle which ones to draw. - if (nodeIsContainedInFrustum && m_debugCtx->m_drawFullyVisibleNodes) + if (nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawFullyVisibleNodes) { auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); } - else if (!nodeIsContainedInFrustum && m_debugCtx->m_drawPartiallyVisibleNodes) + else if (!nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawPartiallyVisibleNodes) { auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); } //Draw bounds on individual objects - if (m_debugCtx->m_drawBoundingBoxes || m_debugCtx->m_drawBoundingSpheres || m_debugCtx->m_drawLodRadii) + if (m_jobData->m_debugCtx->m_drawBoundingBoxes || m_jobData->m_debugCtx->m_drawBoundingSpheres || m_jobData->m_debugCtx->m_drawLodRadii) { for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { Cullable* c = static_cast(visibleEntry->m_userData); - if (m_debugCtx->m_drawBoundingBoxes) + if (m_jobData->m_debugCtx->m_drawBoundingBoxes) { auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(), nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line); } - if (m_debugCtx->m_drawBoundingSpheres) + if (m_jobData->m_debugCtx->m_drawBoundingSpheres) { auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(), Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded); } - if (m_debugCtx->m_drawLodRadii) + if (m_jobData->m_debugCtx->m_drawLodRadii) { auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData.m_lodSelectionRadius, @@ -401,9 +410,9 @@ namespace AZ } } - if (m_debugCtx->m_enableStats) + if (m_jobData->m_debugCtx->m_enableStats) { - CullingDebugContext::CullStats& cullStats = m_debugCtx->GetCullStatsForView(m_view); + CullingDebugContext::CullStats& cullStats = m_jobData->m_debugCtx->GetCullStatsForView(m_jobData->m_view); //no need for mutex here since these are all atomics cullStats.m_numVisibleDrawPackets += numDrawPackets; @@ -411,6 +420,29 @@ namespace AZ ++cullStats.m_numJobs; } } + + MaskedOcclusionCulling::CullingResult TestOcclusionCulling(AzFramework::VisibilityEntry* visibleEntry) + { + if (!m_jobData->m_maskedOcclusionCulling) + { + return MaskedOcclusionCulling::CullingResult::VISIBLE; + } + + // convert the bounding box of the visibility entry to NDC + AZ::Vector4 clipSpaceMin = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMin()); + float depth = clipSpaceMin.GetW(); + AZ::Vector4 ndcMin = clipSpaceMin / clipSpaceMin.GetW(); + + AZ::Vector4 clipSpaceMax = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMax()); + depth = AZStd::min(depth, clipSpaceMax.GetW()); + AZ::Vector4 ndcMax = clipSpaceMax / clipSpaceMax.GetW(); + + Vector2 rectMin(AZStd::min(ndcMin.GetX(), ndcMax.GetX()), AZStd::min(ndcMin.GetY(), ndcMax.GetY())); + Vector2 rectMax(AZStd::max(ndcMin.GetX(), ndcMax.GetX()), AZStd::max(ndcMin.GetY(), ndcMax.GetY())); + + // test against the occlusion buffer, which contains only the manually placed occlusion planes + return m_jobData->m_maskedOcclusionCulling->TestRect(rectMin.GetX(), rectMin.GetY(), rectMax.GetX(), rectMax.GetY(), depth); + } }; void CullingScene::ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob) @@ -444,8 +476,53 @@ namespace AZ cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix(); } + // setup occlusion culling, if necessary + MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); + if (maskedOcclusionCulling) + { + for (const AZ::Transform& transform : m_occlusionCullingPlanes) + { + // find the corners of the plane + static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f); + static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f); + static const Vector3 TL = Vector3(-0.5f, 0.5f, 0.0f); + static const Vector3 TR = Vector3(0.5f, 0.5f, 0.0f); + + Vector3 planeBL = transform.TransformPoint(BL); + Vector3 planeBR = transform.TransformPoint(BR); + Vector3 planeTL = transform.TransformPoint(TL); + Vector3 planeTR = transform.TransformPoint(TR); + + // convert to clip-space + Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(planeBL); + Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(planeBR); + Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(planeTL); + Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(planeTR); + + // store to float array + float verts[16]; + projectedBL.StoreToFloat4(&verts[0]); + projectedBR.StoreToFloat4(&verts[4]); + projectedTL.StoreToFloat4(&verts[8]); + projectedTR.StoreToFloat4(&verts[12]); + + static uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 }; + + // render into the occlusion buffer, specifying BACKFACE_NONE so it functions as a double-sided occluder + maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE); + } + } + WorkListType worklist; - auto nodeVisitorLambda = [this, &scene, &view, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void + + AZStd::shared_ptr jobData = AZStd::make_shared(); + jobData->m_debugCtx = &m_debugCtx; + jobData->m_maskedOcclusionCulling = maskedOcclusionCulling; + jobData->m_scene = &scene; + jobData->m_view = &view; + jobData->m_frustum = frustum; + + auto nodeVisitorLambda = [this, jobData, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "nodeVisitorLambda()"); AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries"); @@ -458,7 +535,7 @@ namespace AZ if (worklist.size() == worklist.capacity()) { //Kick off a job to process the (full) worklist - AddObjectsToViewJob* job = aznew AddObjectsToViewJob(m_debugCtx, scene, view, frustum, worklist); //pool allocated (cheap), auto-deletes when job finishes + AddObjectsToViewJob* job = aznew AddObjectsToViewJob(jobData, worklist); //pool allocated (cheap), auto-deletes when job finishes worklist.clear(); parentJob.SetContinuation(job); job->Start(); @@ -476,8 +553,15 @@ namespace AZ if (worklist.size() > 0) { + AZStd::shared_ptr remainingJobData = AZStd::make_shared(); + remainingJobData->m_debugCtx = &m_debugCtx; + remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling; + remainingJobData->m_scene = &scene; + remainingJobData->m_view = &view; + remainingJobData->m_frustum = frustum; + //Kick off a job to process any remaining workitems - AddObjectsToViewJob* job = aznew AddObjectsToViewJob(m_debugCtx, scene, view, frustum, worklist); //pool allocated (cheap), auto-deletes when job finishes + AddObjectsToViewJob* job = aznew AddObjectsToViewJob(remainingJobData, worklist); //pool allocated (cheap), auto-deletes when job finishes parentJob.SetContinuation(job); job->Start(); } @@ -559,13 +643,18 @@ namespace AZ } } - void CullingScene::BeginCulling(const AZStd::vector& views) + void CullingScene::BeginCulling(const AZStd::vector& views, const AZStd::vector& activePipelines) { m_cullDataConcurrencyCheck.soft_lock(); m_debugCtx.ResetCullStats(); m_debugCtx.m_numCullablesInScene = GetNumCullables(); + for (auto& view : views) + { + view->BeginCulling(activePipelines); + } + AuxGeomDrawPtr auxGeom; if (m_debugCtx.m_debugDraw) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 7e33750eb5..16c2189a00 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -499,7 +500,7 @@ namespace AZ } // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) - m_cullingScene->BeginCulling(m_renderPacket.m_views); + m_cullingScene->BeginCulling(m_renderPacket.m_views, activePipelines); for (ViewPtr& viewPtr : m_renderPacket.m_views) { AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index 21a46693d5..3060fc34a3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -15,7 +15,8 @@ #include #include #include - +#include +#include #include #include @@ -51,6 +52,18 @@ namespace AZ { m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgAsset); } + + m_maskedOcclusionCulling = MaskedOcclusionCulling::Create(); + m_maskedOcclusionCulling->SetNearClipPlane(0.1f); + } + + View::~View() + { + if (m_maskedOcclusionCulling) + { + MaskedOcclusionCulling::Destroy(m_maskedOcclusionCulling); + m_maskedOcclusionCulling = nullptr; + } } void View::SetDrawListMask(const RHI::DrawListMask& drawListMask) @@ -374,5 +387,58 @@ namespace AZ m_shaderResourceGroup->Compile(); m_needBuildSrg = false; } + + void View::BeginCulling(const AZStd::vector& activePipelines) + { + // retrieve current resolution + Vector2 resolution(0.0f, 0.0f); + for (auto& pipeline : activePipelines) + { + ViewPtr pipelineView = pipeline->GetDefaultView(); + if (pipelineView.get() == this) + { + RPI::SwapChainPass* pass = AZ::RPI::PassSystemInterface::Get()->FindSwapChainPass(pipeline->GetWindowHandle()); + if (pass) + { + const RHI::Viewport& viewport = pass->GetViewport(); + resolution.SetX(viewport.m_maxX); + resolution.SetY(viewport.m_maxY); + } + break; + } + } + + // calculate culling resolution based on required tile size for MaskedOcclusionCulling + static const uint32_t MaskedOcclusionCullingSubTileWidth = 8; + static const uint32_t MaskedOcclusionCullingSubTileHeight = 4; + + uint32_t cullingWidth = RHI::AlignUp(resolution.GetX(), MaskedOcclusionCullingSubTileWidth); + uint32_t cullingHeight = RHI::AlignUp(resolution.GetY(), MaskedOcclusionCullingSubTileHeight); + + m_maskedOcclusionCulling->SetResolution(cullingWidth, cullingHeight); + + if (cullingWidth > 0 && cullingHeight > 0) + { + m_maskedOcclusionCulling->ClearBuffer(); + } + } + + MaskedOcclusionCulling* View::GetMaskedOcclusionCulling() + { + if (m_maskedOcclusionCulling) + { + uint32_t width = 0; + uint32_t height = 0; + + m_maskedOcclusionCulling->GetResolution(width, height); + if (width > 0 && height > 0) + { + return m_maskedOcclusionCulling; + } + } + + return nullptr; + } + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake index 0d5c19758b..5ae72fe42f 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake @@ -101,6 +101,7 @@ set(FILES Include/Atom/RPI.Public/GpuQuery/Query.h Include/Atom/RPI.Public/GpuQuery/QueryPool.h Include/Atom/RPI.Public/GpuQuery/TimestampQueryPool.h + Include/Atom/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h Source/RPI.Public/Culling.cpp Source/RPI.Public/FeatureProcessor.cpp Source/RPI.Public/FeatureProcessorFactory.cpp @@ -178,4 +179,7 @@ set(FILES Source/RPI.Public/GpuQuery/Query.cpp Source/RPI.Public/GpuQuery/QueryPool.cpp Source/RPI.Public/GpuQuery/TimestampQueryPool.cpp + Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp + Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp + Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp ) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp index 2ef4e1e229..368d8e76e7 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +116,7 @@ namespace AZ DeferredFogComponent::CreateDescriptor(), SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(), AttachmentComponent::CreateDescriptor(), + OcclusionCullingPlaneComponent::CreateDescriptor(), #ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR EditorAreaLightComponent::CreateDescriptor(), @@ -145,6 +148,7 @@ namespace AZ EditorDeferredFogComponent::CreateDescriptor(), SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(), EditorAttachmentComponent::CreateDescriptor(), + EditorOcclusionCullingPlaneComponent::CreateDescriptor(), #endif }); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp new file mode 100644 index 0000000000..9a655727d6 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp @@ -0,0 +1,91 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + void EditorOcclusionCullingPlaneComponent::Reflect(AZ::ReflectContext* context) + { + BaseClass::Reflect(context); + + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1, ConvertToEditorRenderComponentAdapter<1>) + ; + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class( + "Occlusion Culling Plane", "The OcclusionCullingPlane component is used to cull meshes that are inside the view frustum and behind the occlusion plane") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Category, "Atom") + ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg") + ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.png") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c)) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + + editContext->Class( + "OcclusionCullingPlaneComponentController", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &OcclusionCullingPlaneComponentController::m_configuration, "Configuration", "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ; + + editContext->Class( + "OcclusionCullingPlaneComponentConfig", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ; + } + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("EditorOcclusionCullingPlaneComponentTypeId", BehaviorConstant(Uuid(EditorOcclusionCullingPlaneComponentTypeId))) + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation); + } + } + + EditorOcclusionCullingPlaneComponent::EditorOcclusionCullingPlaneComponent() + { + } + + EditorOcclusionCullingPlaneComponent::EditorOcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config) + : BaseClass(config) + { + } + + void EditorOcclusionCullingPlaneComponent::Activate() + { + BaseClass::Activate(); + AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId()); + } + + void EditorOcclusionCullingPlaneComponent::Deactivate() + { + AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect(); + BaseClass::Deactivate(); + } + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h new file mode 100644 index 0000000000..8070c1d553 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h @@ -0,0 +1,43 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class EditorOcclusionCullingPlaneComponent final + : public EditorRenderComponentAdapter + , private AzFramework::EntityDebugDisplayEventBus::Handler + { + public: + using BaseClass = EditorRenderComponentAdapter; + AZ_EDITOR_COMPONENT(AZ::Render::EditorOcclusionCullingPlaneComponent, EditorOcclusionCullingPlaneComponentTypeId, BaseClass); + + static void Reflect(AZ::ReflectContext* context); + + EditorOcclusionCullingPlaneComponent(); + EditorOcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config); + + // AZ::Component overrides + void Activate() override; + void Deactivate() override; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp new file mode 100644 index 0000000000..567809266d --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp @@ -0,0 +1,43 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include + +namespace AZ +{ + namespace Render + { + OcclusionCullingPlaneComponent::OcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config) + : BaseClass(config) + { + } + + void OcclusionCullingPlaneComponent::Reflect(AZ::ReflectContext* context) + { + BaseClass::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ; + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("OcclusionCullingPlaneComponentTypeId", BehaviorConstant(Uuid(OcclusionCullingPlaneComponentTypeId))) + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common); + } + } + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h new file mode 100644 index 0000000000..7e7b48bd45 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h @@ -0,0 +1,37 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class OcclusionCullingPlaneComponent final + : public AzFramework::Components::ComponentAdapter + { + public: + using BaseClass = AzFramework::Components::ComponentAdapter; + AZ_COMPONENT(AZ::Render::OcclusionCullingPlaneComponent, OcclusionCullingPlaneComponentTypeId, BaseClass); + + OcclusionCullingPlaneComponent() = default; + OcclusionCullingPlaneComponent(const OcclusionCullingPlaneComponentConfig& config); + + static void Reflect(AZ::ReflectContext* context); + }; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h new file mode 100644 index 0000000000..59276de9ee --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentConstants.h @@ -0,0 +1,22 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +namespace AZ +{ + namespace Render + { + static constexpr const char* const OcclusionCullingPlaneComponentTypeId = "{F7537387-15A8-48F0-A1F3-D19C5886B886}"; + static constexpr const char* const EditorOcclusionCullingPlaneComponentTypeId = "{BE7CC17B-32EB-49B0-BAD9-D26E3A059012}"; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp new file mode 100644 index 0000000000..bd03bec0f4 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp @@ -0,0 +1,137 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace AZ +{ + namespace Render + { + void OcclusionCullingPlaneComponentConfig::Reflect(ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ; + } + } + + void OcclusionCullingPlaneComponentController::Reflect(ReflectContext* context) + { + OcclusionCullingPlaneComponentConfig::Reflect(context); + + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("Configuration", &OcclusionCullingPlaneComponentController::m_configuration); + } + } + + void OcclusionCullingPlaneComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + dependent.push_back(AZ_CRC("TransformService", 0x8ee22c50)); + } + + void OcclusionCullingPlaneComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d)); + } + + void OcclusionCullingPlaneComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC("OcclusionCullingPlaneService", 0x9123f33d)); + } + + void OcclusionCullingPlaneComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC("TransformService")); + } + + OcclusionCullingPlaneComponentController::OcclusionCullingPlaneComponentController(const OcclusionCullingPlaneComponentConfig& config) + : m_configuration(config) + { + } + + void OcclusionCullingPlaneComponentController::Activate(AZ::EntityId entityId) + { + m_entityId = entityId; + + TransformNotificationBus::Handler::BusConnect(m_entityId); + + m_featureProcessor = RPI::Scene::GetFeatureProcessorForEntity(entityId); + AZ_Assert(m_featureProcessor, "OcclusionCullingPlaneComponentController was unable to find a OcclusionCullingPlaneFeatureProcessor on the EntityContext provided."); + + m_transformInterface = TransformBus::FindFirstHandler(entityId); + AZ_Assert(m_transformInterface, "Unable to attach to a TransformBus handler"); + if (!m_transformInterface) + { + return; + } + + // add this occlusion plane to the feature processor + const AZ::Transform& transform = m_transformInterface->GetWorldTM(); + m_handle = m_featureProcessor->AddOcclusionCullingPlane(transform); + } + + void OcclusionCullingPlaneComponentController::Deactivate() + { + if (m_featureProcessor) + { + m_featureProcessor->RemoveOcclusionCullingPlane(m_handle); + } + + Data::AssetBus::MultiHandler::BusDisconnect(); + TransformNotificationBus::Handler::BusDisconnect(); + + m_transformInterface = nullptr; + m_featureProcessor = nullptr; + } + + void OcclusionCullingPlaneComponentController::SetConfiguration(const OcclusionCullingPlaneComponentConfig& config) + { + m_configuration = config; + } + + const OcclusionCullingPlaneComponentConfig& OcclusionCullingPlaneComponentController::GetConfiguration() const + { + return m_configuration; + } + + void OcclusionCullingPlaneComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) + { + if (!m_featureProcessor) + { + return; + } + + m_featureProcessor->SetTransform(m_handle, world); + } + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h new file mode 100644 index 0000000000..5f0be5315f --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h @@ -0,0 +1,78 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class OcclusionCullingPlaneComponentConfig final + : public AZ::ComponentConfig + { + public: + AZ_RTTI(AZ::Render::OcclusionCullingPlaneComponentConfig, "{D0E107CA-5AFB-4675-BC97-94BCA5F248DB}", ComponentConfig); + AZ_CLASS_ALLOCATOR(OcclusionCullingPlaneComponentConfig, SystemAllocator, 0); + static void Reflect(AZ::ReflectContext* context); + + OcclusionCullingPlaneComponentConfig() = default; + }; + + class OcclusionCullingPlaneComponentController final + : public Data::AssetBus::MultiHandler + , private TransformNotificationBus::Handler + { + public: + friend class EditorOcclusionCullingPlaneComponent; + + AZ_CLASS_ALLOCATOR(OcclusionCullingPlaneComponentController, AZ::SystemAllocator, 0); + AZ_RTTI(AZ::Render::OcclusionCullingPlaneComponentController, "{8EDA3C7D-5171-4843-9969-4D84DB13F221}"); + + static void Reflect(AZ::ReflectContext* context); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + + OcclusionCullingPlaneComponentController() = default; + OcclusionCullingPlaneComponentController(const OcclusionCullingPlaneComponentConfig& config); + + void Activate(AZ::EntityId entityId); + void Deactivate(); + void SetConfiguration(const OcclusionCullingPlaneComponentConfig& config); + const OcclusionCullingPlaneComponentConfig& GetConfiguration() const; + + private: + + AZ_DISABLE_COPY(OcclusionCullingPlaneComponentController); + + // TransformNotificationBus overrides + void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; + + // handle for this occlusion plane in the feature processor + OcclusionCullingPlaneHandle m_handle; + + OcclusionCullingPlaneFeatureProcessorInterface* m_featureProcessor = nullptr; + TransformInterface* m_transformInterface = nullptr; + AZ::EntityId m_entityId; + OcclusionCullingPlaneComponentConfig m_configuration; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index e58f72a121..360511aaea 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -53,6 +53,8 @@ set(FILES Source/Mesh/EditorMeshSystemComponent.h Source/Mesh/MeshThumbnail.h Source/Mesh/MeshThumbnail.cpp + Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h + Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp Source/PostProcess/EditorPostFxLayerComponent.cpp Source/PostProcess/EditorPostFxLayerComponent.h Source/PostProcess/Bloom/EditorBloomComponent.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake index e13d1d37d6..deb8ab1b74 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake @@ -66,6 +66,10 @@ set(FILES Source/Mesh/MeshComponent.cpp Source/Mesh/MeshComponentController.h Source/Mesh/MeshComponentController.cpp + Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.h + Source/OcclusionCullingPlane/OcclusionCullingPlaneComponent.cpp + Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h + Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp Source/PostProcess/PostFxLayerComponent.cpp Source/PostProcess/PostFxLayerComponent.h Source/PostProcess/PostFxLayerComponentConfig.cpp From bee811ae4ffa6767853233bfe32416ba2a709450 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Thu, 27 May 2021 19:22:46 -0700 Subject: [PATCH 003/153] Moved Simulate to OnBeginPrepareRender. --- .../OcclusionCullingPlaneFeatureProcessor.cpp | 6 ++---- .../OcclusionCullingPlaneFeatureProcessor.h | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp index d4a1a37521..bed008a3da 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp @@ -47,10 +47,8 @@ namespace AZ DisableSceneNotification(); } - void OcclusionCullingPlaneFeatureProcessor::Simulate([[maybe_unused]] const FeatureProcessor::SimulatePacket& packet) - { - AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender); - + void OcclusionCullingPlaneFeatureProcessor::OnBeginPrepareRender() + { AZStd::vector occlusionCullingPlanes; for (auto& occlusionCullingPlane : m_occlusionCullingPlanes) { diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h index c54c816bfd..5319666745 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h @@ -58,7 +58,9 @@ namespace AZ // FeatureProcessor overrides void Activate() override; void Deactivate() override; - void Simulate(const FeatureProcessor::SimulatePacket& packet) override; + + // RPI::SceneNotificationBus overrides ... + void OnBeginPrepareRender() override; // retrieve the full list of occlusion planes using OcclusionCullingPlaneVector = AZStd::vector>; From 802943bbb3bf0553bfaf311608587ed295ff3866 Mon Sep 17 00:00:00 2001 From: karlberg Date: Thu, 27 May 2021 19:54:56 -0700 Subject: [PATCH 004/153] Bug fixes, naming changes to make variables more clear, and adds a cvar to adjust client window size --- Code/LauncherUnified/Launcher.cpp | 16 +++ .../Multiplayer/Components/NetBindComponent.h | 4 + .../Components/NetworkTransformComponent.h | 10 ++ .../EntityReplication/ReplicationRecord.h | 8 +- .../LocalPredictionPlayerInputComponent.cpp | 32 +++--- .../Source/Components/NetBindComponent.cpp | 10 ++ .../Components/NetworkTransformComponent.cpp | 48 ++++++--- .../Source/MultiplayerSystemComponent.cpp | 98 +++++++++++++++++-- .../Code/Source/MultiplayerSystemComponent.h | 4 + .../EntityReplicationManager.cpp | 2 +- .../EntityReplication/PropertyPublisher.cpp | 10 +- .../EntityReplication/ReplicationRecord.cpp | 26 ++--- 12 files changed, 210 insertions(+), 58 deletions(-) diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 1f29478399..acb5cb9dba 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -9,6 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ + #include #include @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include @@ -45,6 +48,19 @@ extern "C" void CreateStaticModules(AZStd::vector& modulesOut); namespace { + void OnViewportResize(const AZ::Vector2& value); + + AZ_CVAR(AZ::Vector2, r_viewportSize, AZ::Vector2::CreateZero(), OnViewportResize, AZ::ConsoleFunctorFlags::DontReplicate, + "The default size for the launcher viewport, 0 0 means full screen"); + + void OnViewportResize(const AZ::Vector2& value) + { + AzFramework::NativeWindowHandle windowHandle = nullptr; + AzFramework::WindowSystemRequestBus::BroadcastResult(windowHandle, &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle); + AzFramework::WindowSize newSize = AzFramework::WindowSize(aznumeric_cast(value.GetX()), aznumeric_cast(value.GetY())); + AzFramework::WindowRequestBus::Broadcast(&AzFramework::WindowRequestBus::Events::ResizeClientArea, newSize); + } + void ExecuteConsoleCommandFile(AzFramework::Application& application) { const AZStd::string_view customConCmdKey = "console-command-file"; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h index 4fe60f14a3..7d9b7d4086 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h @@ -39,6 +39,7 @@ namespace Multiplayer using EntityMigrationStartEvent = AZ::Event; using EntityMigrationEndEvent = AZ::Event<>; using EntityServerMigrationEvent = AZ::Event; + using EntityPreRenderEvent = AZ::Event; //! @class NetBindComponent //! @brief Component that provides net-binding to a networked entity. @@ -97,6 +98,7 @@ namespace Multiplayer void NotifyMigrationStart(ClientInputId migratedInputId); void NotifyMigrationEnd(); void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId); + void NotifyPreRender(float deltaTime, float blendFactor); void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler); void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler); @@ -104,6 +106,7 @@ namespace Multiplayer void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler); void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler); void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler); + void AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler); bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer); @@ -152,6 +155,7 @@ namespace Multiplayer EntityMigrationStartEvent m_entityMigrationStartEvent; EntityMigrationEndEvent m_entityMigrationEndEvent; EntityServerMigrationEvent m_entityServerMigrationEvent; + EntityPreRenderEvent m_entityPreRenderEvent; AZ::Event<> m_onRemove; RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle; AZ::Event<>::Handler m_handleMarkedDirty; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h index 2a3b5fb3cc..0bf913a89a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include namespace Multiplayer @@ -32,13 +33,22 @@ namespace Multiplayer void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; private: + void OnPreRender(float deltaTime, float blendFactor); + void OnRotationChangedEvent(const AZ::Quaternion& rotation); void OnTranslationChangedEvent(const AZ::Vector3& translation); void OnScaleChangedEvent(const AZ::Vector3& scale); + void OnResetCountChangedEvent(); + + AZ::Transform m_previousTransform = AZ::Transform::CreateIdentity(); + AZ::Transform m_targetTransform = AZ::Transform::CreateIdentity(); AZ::Event::Handler m_rotationEventHandler; AZ::Event::Handler m_translationEventHandler; AZ::Event::Handler m_scaleEventHandler; + AZ::Event::Handler m_resetCountEventHandler; + + EntityPreRenderEvent::Handler m_entityPreRenderEventHandler; }; class NetworkTransformComponentController diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h index 3dfc4b8016..33e1e0bde6 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h @@ -45,10 +45,10 @@ namespace Multiplayer static constexpr uint32_t MaxRecordBits = 2048; ReplicationRecord() = default; - ReplicationRecord(NetEntityRole netEntityRole); + ReplicationRecord(NetEntityRole remoteNetEntityRole); - void SetNetworkRole(NetEntityRole netEntityRole); - NetEntityRole GetNetworkRole() const; + void SetRemoteNetworkRole(NetEntityRole remoteNetEntityRole); + NetEntityRole GetRemoteNetworkRole() const; bool AreAllBitsConsumed() const; void ResetConsumedBits(); @@ -92,6 +92,6 @@ namespace Multiplayer // Sequence number this ReplicationRecord was sent on AzNetworking::PacketId m_sentPacketId = AzNetworking::InvalidPacketId; - NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;; + NetEntityRole m_remoteNetEntityRole = NetEntityRole::InvalidRole;; }; } diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 612601883c..99e19a89fd 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -25,6 +25,7 @@ namespace Multiplayer AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay"); #ifndef AZ_RELEASE_BUILD AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat"); + AZ_CVAR(bool, cl_EnableDesyncDebugging, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs"); #endif AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs"); @@ -214,11 +215,12 @@ namespace Multiplayer // Send correction SendClientInputCorrection(GetLastInputId(), correction); -#ifdef _DEBUG - // In debug, show which states caused the correction +#ifndef AZ_RELEASE_BUILD AZStd::string clientStateString; AZStd::string serverStateString; + if (cl_EnableDesyncDebugging) { + // In debug, show which states caused the correction // Write in client state AzNetworking::NetworkOutputSerializer clientStateSerializer(clientState.GetBuffer(), clientState.GetSize()); GetNetBindComponent()->SerializeEntityCorrection(clientStateSerializer); @@ -236,11 +238,13 @@ namespace Multiplayer GetNetBindComponent()->SerializeEntityCorrection(serverValues); AZStd::map> mapComparison; + // put the server value in the first part of the pair for (const auto& pair : serverValues.GetValueMap()) { mapComparison[pair.first].first = pair.second; } + // put the client value in the second part of the pair for (const auto& pair : clientValues.GetValueMap()) { @@ -266,12 +270,13 @@ namespace Multiplayer } } } -#else - const AZStd::string clientStateString = "available in debug only"; - const AZStd::string serverStateString = "available in debug only"; -#endif - + else + { + clientStateString = "available in debug only"; + serverStateString = "available in debug only"; + } AZLOG_ERROR("** Autonomous proxy desync detected! ** clientState=[%s], serverState=[%s]", clientStateString.c_str(), serverStateString.c_str()); +#endif } } } @@ -416,7 +421,7 @@ namespace Multiplayer ClientInputId LocalPredictionPlayerInputComponentController::GetLastInputId() const { - return m_clientInputId; + return m_lastClientInputId; } HostFrameId LocalPredictionPlayerInputComponentController::GetInputFrameId(const NetworkInput& input) const @@ -520,10 +525,13 @@ namespace Multiplayer // In debug, send the entire client output state to the server to make it easier to debug desync issues AzNetworking::PacketEncodingBuffer processInputResult; -#ifdef _DEBUG - AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); - GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); - processInputResult.Resize(processInputResultSerializer.GetSize()); +#ifndef AZ_RELEASE_BUILD + if (cl_EnableDesyncDebugging) + { + AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); + GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); + processInputResult.Resize(processInputResultSerializer.GetSize()); + } #endif // Save this input and discard move history outside our client rewind window diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index d91bba2e0c..0847d42dd6 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -390,6 +390,11 @@ namespace Multiplayer m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId); } + void NetBindComponent::NotifyPreRender(float deltaTime, float blendFactor) + { + m_entityPreRenderEvent.Signal(deltaTime, blendFactor); + } + void NetBindComponent::AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler) { eventHandler.Connect(m_entityStopEvent); @@ -420,6 +425,11 @@ namespace Multiplayer eventHandler.Connect(m_entityServerMigrationEvent); } + void NetBindComponent::AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityPreRenderEvent); + } + bool NetBindComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer) { m_predictableRecord.ResetConsumedBits(); diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index 0cc4cb131e..81b756de50 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -33,6 +33,8 @@ namespace Multiplayer : m_rotationEventHandler([this](const AZ::Quaternion& rotation) { OnRotationChangedEvent(rotation); }) , m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); }) , m_scaleEventHandler([this](const AZ::Vector3& scale) { OnScaleChangedEvent(scale); }) + , m_resetCountEventHandler([this](const uint8_t&) { OnResetCountChangedEvent(); }) + , m_entityPreRenderEventHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); }) { ; } @@ -47,6 +49,11 @@ namespace Multiplayer RotationAddEvent(m_rotationEventHandler); TranslationAddEvent(m_translationEventHandler); ScaleAddEvent(m_scaleEventHandler); + ResetCountAddEvent(m_resetCountEventHandler); + GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler); + + // When coming into relevance, reset all blending factors so we don't interpolate to our start position + OnResetCountChangedEvent(); } void NetworkTransformComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) @@ -56,23 +63,37 @@ namespace Multiplayer void NetworkTransformComponent::OnRotationChangedEvent(const AZ::Quaternion& rotation) { - AZ::Transform worldTm = GetTransformComponent()->GetWorldTM(); - worldTm.SetRotation(rotation); - GetTransformComponent()->SetWorldTM(worldTm); + m_previousTransform.SetRotation(m_targetTransform.GetRotation()); + m_targetTransform.SetRotation(rotation); } void NetworkTransformComponent::OnTranslationChangedEvent(const AZ::Vector3& translation) { - AZ::Transform worldTm = GetTransformComponent()->GetWorldTM(); - worldTm.SetTranslation(translation); - GetTransformComponent()->SetWorldTM(worldTm); + m_previousTransform.SetTranslation(m_targetTransform.GetTranslation()); + m_targetTransform.SetTranslation(translation); } void NetworkTransformComponent::OnScaleChangedEvent(const AZ::Vector3& scale) { - AZ::Transform worldTm = GetTransformComponent()->GetWorldTM(); - worldTm.SetScale(scale); - GetTransformComponent()->SetWorldTM(worldTm); + m_previousTransform.SetScale(m_targetTransform.GetScale()); + m_targetTransform.SetScale(scale); + } + + void NetworkTransformComponent::OnResetCountChangedEvent() + { + m_previousTransform = m_targetTransform; + } + + void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime, float blendFactor) + { + if (!HasController()) + { + AZ::Transform blendTransform; + blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor)); + blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); + blendTransform.SetScale(m_previousTransform.GetScale().Lerp(m_targetTransform.GetScale(), blendFactor)); + GetTransformComponent()->SetWorldTM(blendTransform); + } } @@ -96,11 +117,8 @@ namespace Multiplayer void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& worldTm) { - if (IsAuthority()) - { - SetRotation(worldTm.GetRotation()); - SetTranslation(worldTm.GetTranslation()); - SetScale(worldTm.GetScale()); - } + SetRotation(worldTm.GetRotation()); + SetTranslation(worldTm.GetTranslation()); + SetScale(worldTm.GetScale()); } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index ef8627fe54..485a3719ad 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -12,7 +12,6 @@ #include #include - #include #include #include @@ -24,12 +23,19 @@ #include #include #include +#include #include #include +#include #include #include #include + +#include +#include +#include #include + #include namespace AZ::ConsoleTypeHelpers @@ -74,6 +80,7 @@ namespace Multiplayer AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking"); AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server"); AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything"); + AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update"); AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects"); void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context) @@ -156,10 +163,26 @@ namespace Multiplayer AZ::TickBus::Handler::BusDisconnect(); } - void MultiplayerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + void MultiplayerSystemComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - AZ::TimeMs deltaTimeMs = aznumeric_cast(static_cast(deltaTime * 1000.0f)); - AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs(); + const AZ::TimeMs deltaTimeMs = aznumeric_cast(static_cast(deltaTime * 1000.0f)); + const AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs(); + const AZ::TimeMs serverRateMs = static_cast(sv_serverSendRateMs); + const float serverRateSeconds = static_cast(serverRateMs) / 1000.0f; + + TickVisibleNetworkEntities(deltaTime, serverRateSeconds); + + if (GetAgentType() == MultiplayerAgentType::ClientServer + || GetAgentType() == MultiplayerAgentType::DedicatedServer) + { + m_serverSendAccumulator += deltaTime; + if (m_serverSendAccumulator < serverRateSeconds) + { + return; + } + m_serverSendAccumulator -= serverRateSeconds; + m_networkTime.IncrementHostFrameId(); + } // Handle deferred local rpc messages that were generated during the updates m_networkEntityManager.DispatchLocalDeferredRpcMessages(); @@ -365,13 +388,21 @@ namespace Multiplayer } EntityReplicationManager& replicationManager = reinterpret_cast(connection->GetUserData())->GetReplicationManager(); - - // Ignore a_Request.GetServerGameTimePoint(), clients can't affect the server gametime + + if ((GetAgentType() == MultiplayerAgentType::Client) && (packet.GetHostFrameId() > m_lastReplicatedHostFrameId)) + { + // Update client to latest server time + m_renderBlendFactor = 0.0f; + m_lastReplicatedHostTimeMs = packet.GetHostTimeMs(); + m_lastReplicatedHostFrameId = packet.GetHostFrameId(); + m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId); + } + for (AZStd::size_t i = 0; i < packet.GetEntityMessages().size(); ++i) { const NetworkEntityUpdateMessage& updateMessage = packet.GetEntityMessages()[i]; handledAll &= replicationManager.HandleEntityUpdateMessage(connection, packetHeader, updateMessage); - AZ_Assert(handledAll, "GameServerToClientNetworkRequestHandler EntityUpdates Did not handle all updates"); + AZ_Assert(handledAll, "EntityUpdates did not handle all update messages"); } return handledAll; @@ -439,7 +470,7 @@ namespace Multiplayer } if (GetAgentType() == MultiplayerAgentType::ClientServer - || GetAgentType() == MultiplayerAgentType::DedicatedServer) + || GetAgentType() == MultiplayerAgentType::DedicatedServer) { PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast(sv_defaultPlayerSpawnAsset).c_str()), 1); INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity()); @@ -594,6 +625,57 @@ namespace Multiplayer AZLOG_INFO("Total RPCs received bytes: %llu", aznumeric_cast(rpcsRecv.m_totalBytes)); } + void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds) + { + const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f); + m_renderBlendFactor += targetAdjustBlend; + + // Linear close to the origin, but asymptote at y = 1 + const float adjustedBlendFactor = 1.0f - (std::powf(0.2f, m_renderBlendFactor)); + AZLOG(NET_Blending, "Computed blend factor of %f", adjustedBlendFactor); + + AZ::Transform activeCameraTransform; + Camera::Configuration activeCameraConfiguration; + Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraTransform, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraTransform); + Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraConfiguration, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraConfiguration); + + const AZ::ViewFrustumAttributes frustumAttributes + ( + activeCameraTransform, + activeCameraConfiguration.m_frustumHeight / activeCameraConfiguration.m_frustumWidth, + activeCameraConfiguration.m_fovRadians, + activeCameraConfiguration.m_nearClipDistance, + activeCameraConfiguration.m_farClipDistance + ); + const AZ::Frustum viewFrustum = AZ::Frustum(frustumAttributes); + + // Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system + AZStd::vector gatheredEntities; + AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface::Get(); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum, + [&gatheredEntities, entityBoundsUnion](const AzFramework::IVisibilityScene::NodeData& nodeData) + { + gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + { + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + { + AZ::Entity* entity = static_cast(visEntry->m_userData); + NetBindComponent* netBindComponent = entity->template FindComponent(); + if (netBindComponent != nullptr) + { + gatheredEntities.push_back(netBindComponent); + } + } + } + }); + + for (NetBindComponent* netBindComponent : gatheredEntities) + { + netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + } + } + void MultiplayerSystemComponent::OnConsoleCommandInvoked ( AZStd::string_view command, diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index db83c50fb5..a38bb935a2 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -102,6 +102,7 @@ namespace Multiplayer private: + void TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds); void OnConsoleCommandInvoked(AZStd::string_view command, const AZ::ConsoleCommandContainer& args, AZ::ConsoleFunctorFlags flags, AZ::ConsoleInvokedFrom invokedFrom); void ExecuteConsoleCommandList(AzNetworking::IConnection* connection, const AZStd::fixed_vector& commands); @@ -123,6 +124,9 @@ namespace Multiplayer AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 }; HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId; + double m_serverSendAccumulator = 0.0; + float m_renderBlendFactor = 0.0f; + #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; #endif diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index bd30c5e37f..5d0284dfb2 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -132,7 +132,7 @@ namespace Multiplayer EntityReplicatorList replicatorUpdatedList; MultiplayerPackets::EntityUpdates entityUpdatePacket; entityUpdatePacket.SetHostTimeMs(hostTimeMs); - entityUpdatePacket.SetHostFrameId(InvalidHostFrameId); + entityUpdatePacket.SetHostFrameId(GetNetworkTime()->GetHostFrameId()); // Serialize everything while (!toSendList.empty()) { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp index dfa324f76b..8af636870b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp @@ -27,7 +27,7 @@ namespace Multiplayer , m_sentRecords(net_EntityReplicatorRecordsMax) { AZ_Assert(m_netBindComponent, "NetBindComponent is nullptr"); - m_pendingRecord.SetNetworkRole(remoteNetworkRole); + m_pendingRecord.SetRemoteNetworkRole(remoteNetworkRole); } bool PropertyPublisher::IsDeleting() const @@ -67,7 +67,7 @@ namespace Multiplayer void PropertyPublisher::SetRebasing() { - AZ_Assert(m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous, "Expected to be rebasing on a Autonomous entity"); + AZ_Assert(m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous, "Expected to be rebasing on a Autonomous entity"); m_replicatorState = EntityReplicatorState::Rebasing; } @@ -118,7 +118,7 @@ namespace Multiplayer m_sentRecords.clear(); m_netBindComponent->FillTotalReplicationRecord(m_pendingRecord); // Don't send predictable properties back to the Autonomous unless we correct them - if (m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous) + if (m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous) { m_pendingRecord.Subtract(m_netBindComponent->GetPredictableRecord()); } @@ -137,7 +137,7 @@ namespace Multiplayer // We need to clear out old records, and build up a list of everything that has changed since the last acked packet m_sentRecords.push_front(m_pendingRecord); auto iter = m_sentRecords.begin(); - ++iter; // consider everything after the record we are going to send + ++iter; // Consider everything after the record we are going to send for (; iter != m_sentRecords.end(); ++iter) { // Sequence wasn't acked, so we need to send these bits again @@ -145,7 +145,7 @@ namespace Multiplayer } // Don't send predictable properties back to the Autonomous unless we correct them - if (m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous) + if (m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous) { m_pendingRecord.Subtract(m_netBindComponent->GetPredictableRecord()); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp index 7fe0efd323..47360bfba6 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp @@ -49,19 +49,19 @@ namespace Multiplayer } ReplicationRecord::ReplicationRecord(NetEntityRole netEntityRole) - : m_netEntityRole(netEntityRole) + : m_remoteNetEntityRole(netEntityRole) { ; } - void ReplicationRecord::SetNetworkRole(NetEntityRole netEntityRole) + void ReplicationRecord::SetRemoteNetworkRole(NetEntityRole remoteNetEntityRole) { - m_netEntityRole = netEntityRole; + m_remoteNetEntityRole = remoteNetEntityRole; } - NetEntityRole ReplicationRecord::GetNetworkRole() const + NetEntityRole ReplicationRecord::GetRemoteNetworkRole() const { - return m_netEntityRole; + return m_remoteNetEntityRole; } bool ReplicationRecord::AreAllBitsConsumed() const @@ -196,26 +196,26 @@ namespace Multiplayer bool ReplicationRecord::ContainsAuthorityToClientBits() const { - return (m_netEntityRole != NetEntityRole::Authority) - || (m_netEntityRole == NetEntityRole::InvalidRole); + return (m_remoteNetEntityRole != NetEntityRole::Authority) + || (m_remoteNetEntityRole == NetEntityRole::InvalidRole); } bool ReplicationRecord::ContainsAuthorityToServerBits() const { - return (m_netEntityRole == NetEntityRole::Server) - || (m_netEntityRole == NetEntityRole::InvalidRole); + return (m_remoteNetEntityRole == NetEntityRole::Server) + || (m_remoteNetEntityRole == NetEntityRole::InvalidRole); } bool ReplicationRecord::ContainsAuthorityToAutonomousBits() const { - return (m_netEntityRole == NetEntityRole::Autonomous || m_netEntityRole == NetEntityRole::Server) - || (m_netEntityRole == NetEntityRole::InvalidRole); + return (m_remoteNetEntityRole == NetEntityRole::Autonomous || m_remoteNetEntityRole == NetEntityRole::Server) + || (m_remoteNetEntityRole == NetEntityRole::InvalidRole); } bool ReplicationRecord::ContainsAutonomousToAuthorityBits() const { - return (m_netEntityRole == NetEntityRole::Authority) - || (m_netEntityRole == NetEntityRole::InvalidRole); + return (m_remoteNetEntityRole == NetEntityRole::Authority) + || (m_remoteNetEntityRole == NetEntityRole::InvalidRole); } uint32_t ReplicationRecord::GetRemainingAuthorityToClientBits() const From c84882869bc57887d7e534e803a0c006d516d9fd Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Fri, 28 May 2021 03:41:44 -0700 Subject: [PATCH 005/153] Changed to a fixed-size occlusion buffer --- .../Code/Include/Atom/RPI.Public/Culling.h | 2 +- .../RPI/Code/Include/Atom/RPI.Public/View.h | 2 +- .../RPI/Code/Source/RPI.Public/Culling.cpp | 4 +- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 50 ++----------------- 5 files changed, 9 insertions(+), 51 deletions(-) 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 17e0a1f82d..8892266683 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -217,7 +217,7 @@ namespace AZ void SetOcclusionCullingPlanes(const AZStd::vector& occlusionCullingPlanes) { m_occlusionCullingPlanes = occlusionCullingPlanes; } //! Notifies the CullingScene that culling will begin for this frame. - void BeginCulling(const AZStd::vector& views, const AZStd::vector& activePipelines); + void BeginCulling(const AZStd::vector& views); //! Notifies the CullingScene that the culling is done for this frame. void EndCulling(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index 74c841d2a5..0b6b41c8b0 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -128,7 +128,7 @@ namespace AZ void ConnectWorldToClipMatrixChangedHandler(MatrixChangedEvent::Handler& handler); //! Prepare for view culling - void BeginCulling(const AZStd::vector& activePipelines); + void BeginCulling(); //! Returns the masked occlusion culling interface MaskedOcclusionCulling* GetMaskedOcclusionCulling(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index ab25fb14fb..7bed2d3232 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -643,7 +643,7 @@ namespace AZ } } - void CullingScene::BeginCulling(const AZStd::vector& views, const AZStd::vector& activePipelines) + void CullingScene::BeginCulling(const AZStd::vector& views) { m_cullDataConcurrencyCheck.soft_lock(); @@ -652,7 +652,7 @@ namespace AZ for (auto& view : views) { - view->BeginCulling(activePipelines); + view->BeginCulling(); } AuxGeomDrawPtr auxGeom; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 16c2189a00..c02ac0713c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -500,7 +500,7 @@ namespace AZ } // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs) - m_cullingScene->BeginCulling(m_renderPacket.m_views, activePipelines); + m_cullingScene->BeginCulling(m_renderPacket.m_views); for (ViewPtr& viewPtr : m_renderPacket.m_views) { AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index 3060fc34a3..edae0f88b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -54,7 +54,7 @@ namespace AZ } m_maskedOcclusionCulling = MaskedOcclusionCulling::Create(); - m_maskedOcclusionCulling->SetNearClipPlane(0.1f); + m_maskedOcclusionCulling->SetResolution(1920, 1080); } View::~View() @@ -388,56 +388,14 @@ namespace AZ m_needBuildSrg = false; } - void View::BeginCulling(const AZStd::vector& activePipelines) + void View::BeginCulling() { - // retrieve current resolution - Vector2 resolution(0.0f, 0.0f); - for (auto& pipeline : activePipelines) - { - ViewPtr pipelineView = pipeline->GetDefaultView(); - if (pipelineView.get() == this) - { - RPI::SwapChainPass* pass = AZ::RPI::PassSystemInterface::Get()->FindSwapChainPass(pipeline->GetWindowHandle()); - if (pass) - { - const RHI::Viewport& viewport = pass->GetViewport(); - resolution.SetX(viewport.m_maxX); - resolution.SetY(viewport.m_maxY); - } - break; - } - } - - // calculate culling resolution based on required tile size for MaskedOcclusionCulling - static const uint32_t MaskedOcclusionCullingSubTileWidth = 8; - static const uint32_t MaskedOcclusionCullingSubTileHeight = 4; - - uint32_t cullingWidth = RHI::AlignUp(resolution.GetX(), MaskedOcclusionCullingSubTileWidth); - uint32_t cullingHeight = RHI::AlignUp(resolution.GetY(), MaskedOcclusionCullingSubTileHeight); - - m_maskedOcclusionCulling->SetResolution(cullingWidth, cullingHeight); - - if (cullingWidth > 0 && cullingHeight > 0) - { - m_maskedOcclusionCulling->ClearBuffer(); - } + m_maskedOcclusionCulling->ClearBuffer(); } MaskedOcclusionCulling* View::GetMaskedOcclusionCulling() { - if (m_maskedOcclusionCulling) - { - uint32_t width = 0; - uint32_t height = 0; - - m_maskedOcclusionCulling->GetResolution(width, height); - if (width > 0 && height > 0) - { - return m_maskedOcclusionCulling; - } - } - - return nullptr; + return m_maskedOcclusionCulling; } } // namespace RPI From ab45ea7efa3cacea1e0e809a3bc8e638bf183900 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Fri, 28 May 2021 17:15:20 -0700 Subject: [PATCH 006/153] [ATOM-15631] First pass on exposing Display Mapper properties to Behavior Context --- .../Common/Code/3rdParty/ACES/ACES/Aces.h | 1 + .../DisplayMapperConfigurationDescriptor.h | 8 ++- .../DisplayMapperConfigurationDescriptor.cpp | 26 +++++++++ .../DisplayMapper/DisplayMapperComponentBus.h | 55 +++++++++++++++++++ .../DisplayMapper/DisplayMapperComponent.cpp | 1 - .../DisplayMapperComponentController.cpp | 33 +++++++++++ .../DisplayMapperComponentController.h | 10 ++++ .../EditorDisplayMapperComponent.cpp | 13 ++++- ...egration_commonfeatures_public_files.cmake | 1 + 9 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h diff --git a/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h b/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h index 472ef160be..cd9dca68e3 100644 --- a/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h +++ b/Gems/Atom/Feature/Common/Code/3rdParty/ACES/ACES/Aces.h @@ -177,4 +177,5 @@ namespace AZ } // namespace Render AZ_TYPE_INFO_SPECIALIZE(Render::DisplayMapperOperationType, "{41CA80B1-9E0D-41FB-A235-9638D2A905A5}"); + AZ_TYPE_INFO_SPECIALIZE(Render::OutputDeviceTransformType, "{B94085B7-C0D4-466A-A791-188A4559EC8D}"); } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h index 4dc090b831..22c866447e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DisplayMapper/DisplayMapperConfigurationDescriptor.h @@ -12,11 +12,13 @@ #pragma once +#include + #include + #include #include #include -#include namespace AZ { @@ -33,6 +35,7 @@ namespace AZ AZ_TYPE_INFO(AcesParameterOverrides, "{3EE8C0D4-3792-46C0-B91C-B89A81C36B91}"); static void Reflect(ReflectContext* context); + // Load preconfigured preset for specific ODT mode defined by m_preset void LoadPreset(); // When enabled allows parameter overrides for ACES configuration @@ -98,6 +101,5 @@ namespace AZ DisplayMapperConfigurationDescriptor m_config; }; - - } // namespace RPI + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index e91e125b40..0858381fc5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -23,6 +23,15 @@ namespace AZ { if (auto serializeContext = azrtti_cast(context)) { + serializeContext->Enum() + ->Version(0) + ->Value("48Nits", OutputDeviceTransformType::OutputDeviceTransformType_48Nits) + ->Value("1000Nits", OutputDeviceTransformType::OutputDeviceTransformType_1000Nits) + ->Value("2000Nits", OutputDeviceTransformType::OutputDeviceTransformType_2000Nits) + ->Value("4000Nits", OutputDeviceTransformType::OutputDeviceTransformType_4000Nits) + ->Value("NumOutputDeviceTransformTypes", OutputDeviceTransformType::NumOutputDeviceTransformTypes) + ; + serializeContext->Class() ->Version(0) ->Field("OverrideDefaults", &AcesParameterOverrides::m_overrideDefaults) @@ -38,6 +47,22 @@ namespace AZ ->Field("SurroundGamma", &AcesParameterOverrides::m_surroundGamma) ->Field("Gamma", &AcesParameterOverrides::m_gamma); } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class("AcesParameterOverrides") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Constructor() + ->Method("LoadPreset", &AcesParameterOverrides::LoadPreset) + ->Property("overrideDefaults", BehaviorValueProperty(&AcesParameterOverrides::m_overrideDefaults)) + ->Property("preset", BehaviorValueProperty(&AcesParameterOverrides::m_preset)) + ->Property("alterSurround", BehaviorValueProperty(&AcesParameterOverrides::m_alterSurround)) + ->Property("applyDesaturation", BehaviorValueProperty(&AcesParameterOverrides::m_applyDesaturation)) + ->Property("applyCATD60toD65", BehaviorValueProperty(&AcesParameterOverrides::m_applyCATD60toD65)) + ; + } } void AcesParameterOverrides::LoadPreset() @@ -76,6 +101,7 @@ namespace AZ ->Field("OperationType", &DisplayMapperConfigurationDescriptor::m_operationType) ->Field("LdrGradingLutEnabled", &DisplayMapperConfigurationDescriptor::m_ldrGradingLutEnabled) ->Field("LdrColorGradingLut", &DisplayMapperConfigurationDescriptor::m_ldrColorGradingLut) + ->Field("AcesParameterOverrides", &DisplayMapperConfigurationDescriptor::m_acesParameterOverrides) ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h new file mode 100644 index 0000000000..af57b69d3b --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + struct AcesParameterOverrides; + + //! DisplayMapperComponentRequests provides an interface to request operations on a DisplayMapperComponent + class DisplayMapperComponentRequests + : public ComponentBus + { + public: + //! Load preconfigured preset for specific ODT mode + virtual void LoadPreset(OutputDeviceTransformType preset) = 0; + //! Set display mapper type + virtual void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) = 0; + //! Set custom ACES parameters for ACES mapping, display mapper must be set to Aces to see the difference + virtual void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) = 0; + }; + using DisplayMapperComponentRequestBus = EBus; + + //! DisplayMapperComponent can send out notifications on the DisplayMapperComponentNotifications + class DisplayMapperComponentNotifications : public ComponentBus + { + public: + //! Notifies that display mapper type changed + virtual void OntDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) + { + } + + //! Notifies that ACES parameter overrides changed + virtual void OnAcesParameterOverridesUpdated([[maybe_unused]] const AcesParameterOverrides& acesParameterOverrides) + { + } + }; + using DisplayMapperComponentNotificationBus = EBus; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp index 9642072cd2..b8d8336c30 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponent.cpp @@ -39,6 +39,5 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common); } } - } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 0e283199e7..7831c0a4c6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -76,6 +76,39 @@ namespace AZ return m_configuration; } + void DisplayMapperComponentController::LoadPreset(OutputDeviceTransformType preset) + { + AcesParameterOverrides propertyOverrides; + propertyOverrides.m_preset = preset; + propertyOverrides.m_overrideDefaults = true; + propertyOverrides.LoadPreset(); + SetAcesParameterOverrides(propertyOverrides); + } + + void DisplayMapperComponentController::SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) + { + if (m_configuration.m_displayMapperOperation != displayMapperOperationType) + { + m_configuration.m_displayMapperOperation = displayMapperOperationType; + OnConfigChanged(); + DisplayMapperComponentNotificationBus::Broadcast( + &DisplayMapperComponentNotificationBus::Handler::OntDisplayMapperOperationTypeUpdated, + m_configuration.m_displayMapperOperation); + } + } + + void DisplayMapperComponentController::SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) + { + m_configuration.m_acesParameterOverrides = parameterOverrides; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + DisplayMapperComponentNotificationBus::Broadcast( + &DisplayMapperComponentNotificationBus::Handler::OnAcesParameterOverridesUpdated, + m_configuration.m_acesParameterOverrides); + } + void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h index 3cc6a7e5d9..efa2070828 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h @@ -12,10 +12,12 @@ #pragma once + #include #include #include +#include #include #include @@ -24,7 +26,10 @@ namespace AZ { namespace Render { + struct AcesParameterOverrides; + class DisplayMapperComponentController final + : DisplayMapperComponentRequestBus::Handler { public: friend class EditorDisplayMapperComponent; @@ -43,6 +48,11 @@ namespace AZ void SetConfiguration(const DisplayMapperComponentConfig& config); const DisplayMapperComponentConfig& GetConfiguration() const; + //! DisplayMapperComponentRequestBus::Handler overrides... + void LoadPreset(OutputDeviceTransformType preset) override; + void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) override; + void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) override; + private: AZ_DISABLE_COPY(DisplayMapperComponentController); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index 64cd450940..aadb0cc22b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -76,23 +76,32 @@ namespace AZ Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsBlack, "Cinema Limit (black)", "Reference black luminance value") + ->Attribute(AZ::Edit::Attributes::Min, 0.02f) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_cinemaLimitsWhite) ->DataElement( Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsWhite, "Cinema Limit (white)", "Reference white luminance value") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_cinemaLimitsBlack) + ->Attribute(AZ::Edit::Attributes::Max, 4000) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", "Linear extension below this") + ->Attribute(AZ::Edit::Attributes::Min, 0.002f) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_midPoint) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", - "Middle gray") + Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", "Middle gray") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_minPoint) + ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_maxPoint) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", "Linear extension above this") + ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_midPoint) + ->Attribute(AZ::Edit::Attributes::Max, 4000) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake index 7b8d0a6e21..31a90e7ceb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_public_files.cmake @@ -36,6 +36,7 @@ set(FILES Include/AtomLyIntegration/CommonFeatures/PostProcess/Bloom/BloomComponentConfig.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldBus.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldComponentConfig.h + Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConstants.h Include/AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h From ddbed2f222ec279ef5472df56cc305ef8b29df72 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Fri, 28 May 2021 17:31:33 -0700 Subject: [PATCH 007/153] Sorting occlusion planes. --- .../RPI/Code/Source/RPI.Public/Culling.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 7bed2d3232..e105f7bca5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -480,8 +480,33 @@ namespace AZ MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); if (maskedOcclusionCulling) { + // frustum cull and sort the occlusion planes by view space distance, front-to-back + using OccluderEntry = AZStd::pair; + AZStd::vector visibleOccluders; for (const AZ::Transform& transform : m_occlusionCullingPlanes) { + Aabb occluderAabb = Aabb::CreateCenterHalfExtents(transform.GetTranslation(), AZ::Vector3(AZ::Vector2(transform.GetUniformScale() / 2.0f))); + occluderAabb.SetMin(transform.TransformPoint(occluderAabb.GetMin())); + occluderAabb.SetMax(transform.TransformPoint(occluderAabb.GetMax())); + if (ShapeIntersection::Contains(frustum, occluderAabb)) + { + // occluder is visible, compute view space distance and add to list + float depth = (view.GetWorldToViewMatrix() * occluderAabb.GetMin()).GetZ(); + depth = AZStd::min(depth, (view.GetWorldToViewMatrix() * occluderAabb.GetMax()).GetZ()); + + visibleOccluders.push_back(AZStd::make_pair(transform, depth)); + } + } + + AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const OccluderEntry& LHS, const OccluderEntry& RHS) + { + return LHS.second < RHS.second; + }); + + for (const OccluderEntry& occluder : visibleOccluders) + { + const AZ::Transform& transform = occluder.first; + // find the corners of the plane static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f); static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f); From 59ab6edaefc08768f2b1f933097df07c339103fa Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Mon, 31 May 2021 01:38:13 -0700 Subject: [PATCH 008/153] Added occlusion culling plane visualization --- ...lingPlaneTransparentVisualization.material | 22 ++++ ...cclusionCullingPlaneVisualization.material | 22 ++++ .../Assets/Models/OcclusionCullingPlane.fbx | 3 + ...ionCullingPlaneFeatureProcessorInterface.h | 2 + .../OcclusionCullingPlane.cpp | 113 ++++++++++++++++++ .../OcclusionCullingPlane.h | 65 ++++++++++ .../OcclusionCullingPlaneFeatureProcessor.cpp | 13 ++ .../OcclusionCullingPlaneFeatureProcessor.h | 21 +--- .../Code/atom_feature_common_files.cmake | 2 + .../RPI/Code/Source/RPI.Public/Culling.cpp | 72 ++++++++--- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 6 +- .../EditorOcclusionCullingPlaneComponent.cpp | 6 +- ...clusionCullingPlaneComponentController.cpp | 8 +- ...OcclusionCullingPlaneComponentController.h | 3 + 14 files changed, 321 insertions(+), 37 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneTransparentVisualization.material create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneVisualization.material create mode 100644 Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx create mode 100644 Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.h diff --git a/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneTransparentVisualization.material b/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneTransparentVisualization.material new file mode 100644 index 0000000000..981e392eef --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneTransparentVisualization.material @@ -0,0 +1,22 @@ +{ + "materialType": "Materials\\Types\\StandardPBR.materialtype", + "propertyLayoutVersion": 3, + "properties": { + "general": { + "enableShadows": false, + "enableDirectionalLights": false, + "enablePunctualLights": false, + "enableAreaLights": false, + "enableIBL": true + }, + "baseColor": { + "color": [ 0.0, 1.0, 0.0 ] + }, + "opacity": { + "alphaSource": "None", + "doubleSided": true, + "factor": 0.25, + "mode": "TintedTransparent" + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneVisualization.material b/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneVisualization.material new file mode 100644 index 0000000000..4446cc2d9d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/OcclusionCullingPlane/OcclusionCullingPlaneVisualization.material @@ -0,0 +1,22 @@ +{ + "materialType": "Materials\\Types\\StandardPBR.materialtype", + "propertyLayoutVersion": 3, + "properties": { + "general": { + "enableShadows": false, + "enableDirectionalLights": false, + "enablePunctualLights": false, + "enableAreaLights": false, + "enableIBL": true + }, + "baseColor": { + "color": [ 0.0, 1.0, 0.0 ] + }, + "opacity": { + "alphaSource": "None", + "doubleSided": true, + "factor": 1.0, + "mode": "TintedTransparent" + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx b/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx new file mode 100644 index 0000000000..b274bfa282 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a1f8d75dcd85e8b4aa57f6c0c81af0300ff96915ba3c2b591095c215d5e1d8c +size 12072 diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h index 07a6179e78..8ffbb7f235 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessorInterface.h @@ -36,6 +36,8 @@ namespace AZ virtual bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const = 0; virtual void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) = 0; virtual void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled) = 0; + virtual void ShowVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool showVisualization) = 0; + virtual void SetTransparentVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool transparentVisualization) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp new file mode 100644 index 0000000000..10004a72e4 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp @@ -0,0 +1,113 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + static const char* OcclusionCullingPlaneDrawListTag("occlusioncullingplanevisualization"); + + OcclusionCullingPlane::~OcclusionCullingPlane() + { + Data::AssetBus::MultiHandler::BusDisconnect(); + m_meshFeatureProcessor->ReleaseMesh(m_visualizationMeshHandle); + } + + void OcclusionCullingPlane::Init(RPI::Scene* scene) + { + AZ_Assert(scene, "OcclusionCullingPlane::Init called with a null Scene pointer"); + + m_meshFeatureProcessor = scene->GetFeatureProcessor(); + + // load visualization plane model and material + m_visualizationModelAsset = AZ::RPI::AssetUtils::GetAssetByProductPath( + "Models/OcclusionCullingPlane.azmodel", + AZ::RPI::AssetUtils::TraceLevel::Assert); + + m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(m_visualizationModelAsset); + m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_visualizationMeshHandle, true); + m_meshFeatureProcessor->SetRayTracingEnabled(m_visualizationMeshHandle, false); + m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, AZ::Transform::CreateIdentity()); + + SetVisualizationMaterial(); + } + + void OcclusionCullingPlane::SetVisualizationMaterial() + { + AZStd::string materialAssetPath; + if (m_transparentVisualization) + { + materialAssetPath = "Materials/OcclusionCullingPlane/OcclusionCullingPlaneTransparentVisualization.azmaterial"; + } + else + { + materialAssetPath = "Materials/OcclusionCullingPlane/OcclusionCullingPlaneVisualization.azmaterial"; + } + + RPI::AssetUtils::TraceLevel traceLevel = AZ::RPI::AssetUtils::TraceLevel::Assert; + m_visualizationMaterialAsset = AZ::RPI::AssetUtils::GetAssetByProductPath(materialAssetPath.c_str(), traceLevel); + m_visualizationMaterialAsset.QueueLoad(); + Data::AssetBus::MultiHandler::BusConnect(m_visualizationMaterialAsset.GetId()); + } + + void OcclusionCullingPlane::OnAssetReady(Data::Asset asset) + { + if (m_visualizationMaterialAsset.GetId() == asset.GetId()) + { + m_visualizationMaterialAsset = asset; + Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId()); + + m_visualizationMaterial = AZ::RPI::Material::FindOrCreate(m_visualizationMaterialAsset); + m_meshFeatureProcessor->SetMaterialAssignmentMap(m_visualizationMeshHandle, m_visualizationMaterial); + } + } + + void OcclusionCullingPlane::OnAssetError(Data::Asset asset) + { + AZ_Error("OcclusionCullingPlane", false, "Failed to load OcclusionCullingPlane visualization asset %s", asset.ToString().c_str()); + Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId()); + } + + void OcclusionCullingPlane::SetTransform(const AZ::Transform& transform) + { + m_transform = transform; + + // update visualization plane transform + m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, transform); + } + + void OcclusionCullingPlane::ShowVisualization(bool showVisualization) + { + if (m_showVisualization != showVisualization) + { + m_meshFeatureProcessor->SetVisible(m_visualizationMeshHandle, showVisualization); + SetVisualizationMaterial(); + } + } + + void OcclusionCullingPlane::SetTransparentVisualization(bool transparentVisualization) + { + if (m_transparentVisualization != transparentVisualization) + { + m_transparentVisualization = transparentVisualization; + SetVisualizationMaterial(); + } + } + + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.h b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.h new file mode 100644 index 0000000000..4701c4977f --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlane.h @@ -0,0 +1,65 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AZ +{ + namespace Render + { + //! This class represents an OcclusionCullingPlane which is used to cull meshes that are inside the view frustum + class OcclusionCullingPlane final + : public AZ::Data::AssetBus::MultiHandler + { + public: + OcclusionCullingPlane() = default; + ~OcclusionCullingPlane(); + + void Init(RPI::Scene* scene); + + void SetTransform(const AZ::Transform& transform); + const AZ::Transform& GetTransform() const { return m_transform; } + + void SetEnabled(bool enabled) { m_enabled = enabled; } + bool GetEnabled() const { return m_enabled; } + + // enables or disables rendering of the visualization plane + void ShowVisualization(bool showVisualization); + + // sets the visualization to transparent mode + void SetTransparentVisualization(bool transparentVisualization); + + private: + + void SetVisualizationMaterial(); + + // AZ::Data::AssetBus::Handler overrides... + void OnAssetReady(Data::Asset asset) override; + void OnAssetError(Data::Asset asset) override; + + AZ::Transform m_transform; + bool m_enabled = true; + bool m_showVisualization = true; + bool m_transparentVisualization = false; + + // visualization + AZ::Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr; + Data::Asset m_visualizationModelAsset; + Data::Asset m_visualizationMaterialAsset; + Data::Instance m_visualizationMaterial; + AZ::Render::MeshFeatureProcessorInterface::MeshHandle m_visualizationMeshHandle; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp index bed008a3da..b9866a925f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp @@ -60,6 +60,7 @@ namespace AZ OcclusionCullingPlaneHandle OcclusionCullingPlaneFeatureProcessor::AddOcclusionCullingPlane(const AZ::Transform& transform) { AZStd::shared_ptr occlusionCullingPlane = AZStd::make_shared(); + occlusionCullingPlane->Init(GetParentScene()); occlusionCullingPlane->SetTransform(transform); m_occlusionCullingPlanes.push_back(occlusionCullingPlane); return occlusionCullingPlane; @@ -90,5 +91,17 @@ namespace AZ AZ_Assert(occlusionCullingPlane.get(), "Enable called with an invalid handle"); occlusionCullingPlane->SetEnabled(enabled); } + + void OcclusionCullingPlaneFeatureProcessor::ShowVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool showVisualization) + { + AZ_Assert(occlusionCullingPlane.get(), "ShowVisualization called with an invalid handle"); + occlusionCullingPlane->ShowVisualization(showVisualization); + } + + void OcclusionCullingPlaneFeatureProcessor::SetTransparentVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool transparentVisualization) + { + AZ_Assert(occlusionCullingPlane.get(), "SetTransparentVisualization called with an invalid handle"); + occlusionCullingPlane->SetTransparentVisualization(transparentVisualization); + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h index 5319666745..211254742f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h @@ -13,29 +13,12 @@ #pragma once #include +#include namespace AZ { namespace Render { - //! This class represents an OcclusionCullingPlane which is used to cull meshes that are inside the view frustum - class OcclusionCullingPlane final - { - public: - OcclusionCullingPlane() = default; - ~OcclusionCullingPlane() = default; - - void SetTransform(const AZ::Transform& transform) { m_transform = transform; } - const AZ::Transform& GetTransform() const { return m_transform; } - - void SetEnabled(bool enabled) { m_enabled = enabled; } - bool GetEnabled() const { return m_enabled; } - - private: - AZ::Transform m_transform; - bool m_enabled = true; - }; - //! This class manages OcclusionCullingPlanes which are used to cull meshes that are inside the view frustum class OcclusionCullingPlaneFeatureProcessor final : public OcclusionCullingPlaneFeatureProcessorInterface @@ -54,6 +37,8 @@ namespace AZ bool IsValidOcclusionCullingPlaneHandle(const OcclusionCullingPlaneHandle& occlusionCullingPlane) const override { return (occlusionCullingPlane.get() != nullptr); } void SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) override; void SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enable) override; + void ShowVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool showVisualization) override; + void SetTransparentVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool transparentVisualization) override; // FeatureProcessor overrides void Activate() override; diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index c545a2c974..b796a5b356 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -175,6 +175,8 @@ set(FILES Source/MorphTargets/MorphTargetDispatchItem.h Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp + Source/OcclusionCullingPlane/OcclusionCullingPlane.h + Source/OcclusionCullingPlane/OcclusionCullingPlane.cpp Source/PostProcess/PostProcessBase.cpp Source/PostProcess/PostProcessBase.h Source/PostProcess/PostProcessFeatureProcessor.cpp diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index e105f7bca5..d8ed850309 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -428,20 +428,52 @@ namespace AZ return MaskedOcclusionCulling::CullingResult::VISIBLE; } - // convert the bounding box of the visibility entry to NDC - AZ::Vector4 clipSpaceMin = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMin()); - float depth = clipSpaceMin.GetW(); - AZ::Vector4 ndcMin = clipSpaceMin / clipSpaceMin.GetW(); + if (visibleEntry->m_boundingVolume.Contains(m_jobData->m_view->GetCameraTransform().GetTranslation())) + { + // camera is inside bounding volume + return MaskedOcclusionCulling::CullingResult::VISIBLE; + } - AZ::Vector4 clipSpaceMax = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(visibleEntry->m_boundingVolume.GetMax()); - depth = AZStd::min(depth, clipSpaceMax.GetW()); - AZ::Vector4 ndcMax = clipSpaceMax / clipSpaceMax.GetW(); + const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin(); + const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax(); - Vector2 rectMin(AZStd::min(ndcMin.GetX(), ndcMax.GetX()), AZStd::min(ndcMin.GetY(), ndcMax.GetY())); - Vector2 rectMax(AZStd::max(ndcMin.GetX(), ndcMax.GetX()), AZStd::max(ndcMin.GetY(), ndcMax.GetY())); + // compute bounding volume corners + Vector4 corners[8]; + corners[0] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); + corners[1] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); + corners[2] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); + corners[3] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); + corners[4] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); + corners[5] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); + corners[6] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); + corners[7] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); + // find min clip-space depth and NDC min/max + float ndcMinX = FLT_MAX; + float ndcMinY = FLT_MAX; + float ndcMaxX = -FLT_MAX; + float ndcMaxY = -FLT_MAX; + float minDepth = FLT_MAX; + for (uint32_t index = 0; index < 8; ++index) + { + minDepth = AZStd::min(minDepth, corners[index].GetW()); + + // convert to NDC + corners[index] /= corners[index].GetW(); + + ndcMinX = AZStd::min(ndcMinX, corners[index].GetX()); + ndcMinY = AZStd::min(ndcMinY, corners[index].GetY()); + ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX()); + ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY()); + } + + if (minDepth < 0.00000001f) + { + return MaskedOcclusionCulling::VISIBLE; + } + // test against the occlusion buffer, which contains only the manually placed occlusion planes - return m_jobData->m_maskedOcclusionCulling->TestRect(rectMin.GetX(), rectMin.GetY(), rectMax.GetX(), rectMax.GetY(), depth); + return m_jobData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth); } }; @@ -480,15 +512,22 @@ namespace AZ MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); if (maskedOcclusionCulling) { - // frustum cull and sort the occlusion planes by view space distance, front-to-back + // frustum cull occlusion planes using OccluderEntry = AZStd::pair; AZStd::vector visibleOccluders; for (const AZ::Transform& transform : m_occlusionCullingPlanes) { - Aabb occluderAabb = Aabb::CreateCenterHalfExtents(transform.GetTranslation(), AZ::Vector3(AZ::Vector2(transform.GetUniformScale() / 2.0f))); - occluderAabb.SetMin(transform.TransformPoint(occluderAabb.GetMin())); - occluderAabb.SetMax(transform.TransformPoint(occluderAabb.GetMax())); - if (ShapeIntersection::Contains(frustum, occluderAabb)) + static const AZ::Vector3 BL(-0.5f, -0.5f, 0.0f); + static const AZ::Vector3 TR(0.5f, 0.5f, 0.0f); + + AZ::Vector3 P1 = transform.TransformPoint(BL); + AZ::Vector3 P2 = transform.TransformPoint(TR); + + AZ::Vector3 aabbMin = P1.GetMin(P2); + AZ::Vector3 aabbMax = P1.GetMax(P2); + + AZ::Aabb occluderAabb = Aabb::CreateFromMinMax(aabbMin, aabbMax); + if (ShapeIntersection::Overlaps(frustum, occluderAabb)) { // occluder is visible, compute view space distance and add to list float depth = (view.GetWorldToViewMatrix() * occluderAabb.GetMin()).GetZ(); @@ -498,9 +537,10 @@ namespace AZ } } + // sort the occlusion planes by view space distance, front-to-back AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const OccluderEntry& LHS, const OccluderEntry& RHS) { - return LHS.second < RHS.second; + return LHS.second > RHS.second; }); for (const OccluderEntry& occluder : visibleOccluders) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index edae0f88b7..6e4dec112f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -28,6 +28,10 @@ namespace AZ { namespace RPI { + // fixed-size software occlusion culling buffer + const uint32_t MaskedSoftwareOcclusionCullingWidth = 1920; + const uint32_t MaskedSoftwareOcclusionCullingHeight = 1080; + ViewPtr View::CreateView(const AZ::Name& name, UsageFlags usage) { View* view = aznew View(name, usage); @@ -54,7 +58,7 @@ namespace AZ } m_maskedOcclusionCulling = MaskedOcclusionCulling::Create(); - m_maskedOcclusionCulling->SetResolution(1920, 1080); + m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight); } View::~View() diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp index 9a655727d6..b027be3171 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp @@ -53,8 +53,12 @@ namespace AZ editContext->Class( "OcclusionCullingPlaneComponentConfig", "") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->ClassElement(AZ::Edit::ClassElements::Group, "Settings") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &OcclusionCullingPlaneComponentConfig::m_showVisualization, "Show Visualization", "Show the occlusion culling plane visualization") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &OcclusionCullingPlaneComponentConfig::m_transparentVisualization, "Transparent Visualization", "Sets the occlusion culling plane visualization as transparent") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp index bd03bec0f4..cf8107776f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.cpp @@ -38,7 +38,9 @@ namespace AZ { serializeContext->Class() ->Version(0) - ; + ->Field("ShowVisualization", &OcclusionCullingPlaneComponentConfig::m_showVisualization) + ->Field("TransparentVisualization", &OcclusionCullingPlaneComponentConfig::m_transparentVisualization) + ; } } @@ -98,6 +100,10 @@ namespace AZ // add this occlusion plane to the feature processor const AZ::Transform& transform = m_transformInterface->GetWorldTM(); m_handle = m_featureProcessor->AddOcclusionCullingPlane(transform); + + // set visualization + m_featureProcessor->ShowVisualization(m_handle, m_configuration.m_showVisualization); + m_featureProcessor->SetTransparentVisualization(m_handle, m_configuration.m_transparentVisualization); } void OcclusionCullingPlaneComponentController::Deactivate() diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h index 5f0be5315f..2d977a2cf3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneComponentController.h @@ -32,6 +32,9 @@ namespace AZ AZ_CLASS_ALLOCATOR(OcclusionCullingPlaneComponentConfig, SystemAllocator, 0); static void Reflect(AZ::ReflectContext* context); + bool m_showVisualization = true; + bool m_transparentVisualization = false; + OcclusionCullingPlaneComponentConfig() = default; }; From a9a42a540550507258b77b5fed933bf73a267734 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Tue, 1 Jun 2021 12:17:48 -0700 Subject: [PATCH 009/153] Added AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED --- Gems/Atom/RPI/Code/CMakeLists.txt | 17 ++++++++-- .../Code/Include/Atom/RPI.Public/Culling.h | 1 - .../RPI/Code/Include/Atom/RPI.Public/View.h | 3 +- .../Android/Atom_RPI_Traits_Android.h | 14 +++++++++ .../Android/Atom_RPI_Traits_Platform.h | 14 +++++++++ .../Android/platform_android_files.cmake | 15 +++++++++ .../Platform/Linux/Atom_RPI_Traits_Linux.h | 14 +++++++++ .../Platform/Linux/Atom_RPI_Traits_Platform.h | 14 +++++++++ .../Platform/Linux/platform_linux_files.cmake | 15 +++++++++ .../Source/Platform/Mac/Atom_RPI_Traits_Mac.h | 14 +++++++++ .../Platform/Mac/Atom_RPI_Traits_Platform.h | 14 +++++++++ .../Platform/Mac/platform_mac_files.cmake | 15 +++++++++ .../Windows/Atom_RPI_Traits_Platform.h | 14 +++++++++ .../Windows/Atom_RPI_Traits_Windows.h | 14 +++++++++ .../Source/Platform/Windows/PAL_windows.cmake | 7 +++-- .../Windows/platform_windows_files.cmake | 15 +++++++++ .../Platform/iOS/Atom_RPI_Traits_Platform.h | 14 +++++++++ .../Source/Platform/iOS/Atom_RPI_Traits_iOS.h | 14 +++++++++ .../Platform/iOS/platform_ios_files.cmake | 15 +++++++++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 31 +++++++++++++++---- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 13 ++++++-- .../atom_rpi_masked_occlusion_files.cmake | 18 +++++++++++ .../Atom/RPI/Code/atom_rpi_public_files.cmake | 6 +--- 23 files changed, 291 insertions(+), 20 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Android.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Linux.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Mac.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Platform.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Windows.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake create mode 100644 Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_iOS.h create mode 100644 Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake create mode 100644 Gems/Atom/RPI/Code/atom_rpi_masked_occlusion_files.cmake diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index d2b7fba071..2898967add 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -9,6 +9,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) + +#for PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED and PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED +include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + +if(PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED) + set(MASKED_OCCLUSION_CULLING_FILES "atom_rpi_masked_occlusion_files.cmake") +else() + set(MASKED_OCCLUSION_CULLING_FILES "") +endif() + ly_add_target( NAME Atom_RPI.Public STATIC NAMESPACE Gem @@ -16,11 +27,15 @@ ly_add_target( atom_rpi_reflect_files.cmake atom_rpi_public_files.cmake ../Assets/atom_rpi_asset_files.cmake + ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + ${MASKED_OCCLUSION_CULLING_FILES} INCLUDE_DIRECTORIES PRIVATE Source + ${pal_source_dir} PUBLIC Include + External BUILD_DEPENDENCIES PRIVATE AZ::AtomCore @@ -159,8 +174,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common) - include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) #for PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED - if(NOT PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED) # Create a stub 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 8892266683..3f03fb9dcb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index 0b6b41c8b0..7d192ea62a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -18,13 +18,14 @@ #include #include #include -#include #include #include #include #include +class MaskedOcclusionCulling; + namespace AZ { namespace RHI diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Android.h b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Android.h new file mode 100644 index 0000000000..e1c8d827bf --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Android.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED 0 diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h new file mode 100644 index 0000000000..27e0af7f35 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Atom_Feature_Traits_Android.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake new file mode 100644 index 0000000000..357d8f0381 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake @@ -0,0 +1,15 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + Atom_Feature_Traits_Platform.h + Atom_Feature_Traits_Android.h +) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Linux.h b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Linux.h new file mode 100644 index 0000000000..e1c8d827bf --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Linux.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED 0 diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h new file mode 100644 index 0000000000..39c6a3e572 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Atom_Feature_Traits_Linux.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake new file mode 100644 index 0000000000..19be7951f6 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake @@ -0,0 +1,15 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + Atom_Feature_Traits_Platform.h + Atom_Feature_Traits_Linux.h +) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Mac.h b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Mac.h new file mode 100644 index 0000000000..e1c8d827bf --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Mac.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED 0 diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h new file mode 100644 index 0000000000..19816f2bd1 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Atom_Feature_Traits_Mac.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake new file mode 100644 index 0000000000..bde67ff340 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake @@ -0,0 +1,15 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + Atom_Feature_Traits_Platform.h + Atom_Feature_Traits_Mac.h +) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Platform.h new file mode 100644 index 0000000000..dc655ed3a9 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Atom_RPI_Traits_Windows.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Windows.h b/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Windows.h new file mode 100644 index 0000000000..0deebe4706 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/Atom_RPI_Traits_Windows.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED 1 diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake b/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake index 51e42d5216..b989233ccd 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/PAL_windows.cmake @@ -10,16 +10,17 @@ # set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED TRUE) +set (PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED TRUE) ly_add_source_properties( - SOURCES Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp + SOURCES External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp PROPERTY COMPILE_OPTIONS VALUES /arch:AVX2 /W3 ) ly_add_source_properties( SOURCES - Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp - Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp + External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp + External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp PROPERTY COMPILE_OPTIONS VALUES /W3 ) \ No newline at end of file diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake new file mode 100644 index 0000000000..e49944d8ef --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake @@ -0,0 +1,15 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + Atom_RPI_Traits_Platform.h + Atom_RPI_Traits_Windows.h +) diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h new file mode 100644 index 0000000000..4403d741dc --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Atom_Feature_Traits_iOS.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_iOS.h b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_iOS.h new file mode 100644 index 0000000000..e1c8d827bf --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_iOS.h @@ -0,0 +1,14 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#define AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED 0 diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake new file mode 100644 index 0000000000..7f603e4bfd --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake @@ -0,0 +1,15 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + Atom_Feature_Traits_Platform.h + Atom_Feature_Traits_iOS.h +) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index d8ed850309..79d152f661 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -20,15 +20,20 @@ #include +#include #include #include - #include #include #include #include #include #include +#include + +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED +#include +#endif //Enables more inner-loop profiling scopes (can create high overhead in RadTelemetry if there are many-many objects in a scene) //#define AZ_CULL_PROFILE_DETAILED @@ -265,10 +270,12 @@ namespace AZ struct JobData { CullingDebugContext* m_debugCtx = nullptr; - MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; const Scene* m_scene = nullptr; View* m_view = nullptr; Frustum m_frustum; +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; +#endif }; private: @@ -308,7 +315,9 @@ namespace AZ //Add all objects within this node to the view, without any extra culling for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) +#endif { if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { @@ -347,7 +356,9 @@ namespace AZ } else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_jobData->m_frustum, c->m_cullData.m_boundingObb)) { +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) +#endif { numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); ++numVisibleCullables; @@ -421,6 +432,7 @@ namespace AZ } } +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED MaskedOcclusionCulling::CullingResult TestOcclusionCulling(AzFramework::VisibilityEntry* visibleEntry) { if (!m_jobData->m_maskedOcclusionCulling) @@ -471,10 +483,11 @@ namespace AZ { return MaskedOcclusionCulling::VISIBLE; } - + // test against the occlusion buffer, which contains only the manually placed occlusion planes return m_jobData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth); } +#endif }; void CullingScene::ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob) @@ -508,6 +521,7 @@ namespace AZ cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix(); } +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED // setup occlusion culling, if necessary MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); if (maskedOcclusionCulling) @@ -577,15 +591,19 @@ namespace AZ maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE); } } +#endif WorkListType worklist; AZStd::shared_ptr jobData = AZStd::make_shared(); jobData->m_debugCtx = &m_debugCtx; - jobData->m_maskedOcclusionCulling = maskedOcclusionCulling; jobData->m_scene = &scene; jobData->m_view = &view; jobData->m_frustum = frustum; +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + jobData->m_maskedOcclusionCulling = maskedOcclusionCulling; +#endif + auto nodeVisitorLambda = [this, jobData, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void { @@ -620,11 +638,12 @@ namespace AZ { AZStd::shared_ptr remainingJobData = AZStd::make_shared(); remainingJobData->m_debugCtx = &m_debugCtx; - remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling; remainingJobData->m_scene = &scene; remainingJobData->m_view = &view; remainingJobData->m_frustum = frustum; - +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling; +#endif //Kick off a job to process any remaining workitems AddObjectsToViewJob* job = aznew AddObjectsToViewJob(remainingJobData, worklist); //pool allocated (cheap), auto-deletes when job finishes parentJob.SetContinuation(job); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index 6e4dec112f..bd0e15fb2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -23,6 +23,11 @@ #include #include #include +#include + +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED +#include +#endif namespace AZ { @@ -56,18 +61,21 @@ namespace AZ { m_shaderResourceGroup = ShaderResourceGroup::Create(viewSrgAsset); } - +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED m_maskedOcclusionCulling = MaskedOcclusionCulling::Create(); m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight); +#endif } View::~View() { +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED if (m_maskedOcclusionCulling) { MaskedOcclusionCulling::Destroy(m_maskedOcclusionCulling); m_maskedOcclusionCulling = nullptr; } +#endif } void View::SetDrawListMask(const RHI::DrawListMask& drawListMask) @@ -394,13 +402,14 @@ namespace AZ void View::BeginCulling() { +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED m_maskedOcclusionCulling->ClearBuffer(); +#endif } MaskedOcclusionCulling* View::GetMaskedOcclusionCulling() { return m_maskedOcclusionCulling; } - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/atom_rpi_masked_occlusion_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_masked_occlusion_files.cmake new file mode 100644 index 0000000000..5828848c81 --- /dev/null +++ b/Gems/Atom/RPI/Code/atom_rpi_masked_occlusion_files.cmake @@ -0,0 +1,18 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set(FILES + External/MaskedOcclusionCulling/MaskedOcclusionCulling.h + External/MaskedOcclusionCulling/MaskedOcclusionCullingCommon.inl + External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp + External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp + External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp +) \ No newline at end of file diff --git a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake index 35003d268a..a1d98bbd38 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_public_files.cmake @@ -102,7 +102,6 @@ set(FILES Include/Atom/RPI.Public/GpuQuery/Query.h Include/Atom/RPI.Public/GpuQuery/QueryPool.h Include/Atom/RPI.Public/GpuQuery/TimestampQueryPool.h - Include/Atom/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h Source/RPI.Public/Culling.cpp Source/RPI.Public/FeatureProcessor.cpp Source/RPI.Public/FeatureProcessorFactory.cpp @@ -181,7 +180,4 @@ set(FILES Source/RPI.Public/GpuQuery/Query.cpp Source/RPI.Public/GpuQuery/QueryPool.cpp Source/RPI.Public/GpuQuery/TimestampQueryPool.cpp - Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp - Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp - Source/RPI.Public/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp -) +) \ No newline at end of file From 38819c630aa7313c49cb8073876b6f401df95efb Mon Sep 17 00:00:00 2001 From: mnaumov Date: Tue, 1 Jun 2021 15:34:01 -0700 Subject: [PATCH 010/153] PR feedback --- .../DisplayMapper/DisplayMapperComponentBus.h | 63 ++++- .../DisplayMapperComponentController.cpp | 231 +++++++++++++++++- .../DisplayMapperComponentController.h | 24 ++ .../EditorDisplayMapperComponent.cpp | 60 +++-- 4 files changed, 359 insertions(+), 19 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h index af57b69d3b..4a01f71325 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -30,8 +30,67 @@ namespace AZ virtual void LoadPreset(OutputDeviceTransformType preset) = 0; //! Set display mapper type virtual void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) = 0; - //! Set custom ACES parameters for ACES mapping, display mapper must be set to Aces to see the difference + //! Get display mapper type + virtual DisplayMapperOperationType GetDisplayMapperOperationType() const = 0; + //! Set ACES parameter overrides for ACES mapping, display mapper must be set to Aces to see the difference virtual void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) = 0; + //! Get ACES parameter overrides + virtual const AcesParameterOverrides& GetAcesParameterOverrides() const = 0; + + // Enable or disable ACES parameter overrides + virtual void SetOverrideAcesParameters(bool value) = 0; + // Check if ACES parameters are overriding default preset values + virtual bool GetOverrideAcesParameters() const = 0; + + // Set gamma adjustment to compensate for dim surround + virtual void SetAlterSurround(bool value) = 0; + // Get gamma adjustment to compensate for dim surround + virtual bool GetAlterSurround() const = 0; + + // Set desaturation to compensate for luminance difference + virtual void SetApplyDesaturation(bool value) = 0; + // Get desaturation to compensate for luminance difference + virtual bool GetApplyDesaturation() const = 0; + + // Set color appearance transform (CAT) from ACES white point to assumed observer adapted white point + virtual void SetApplyCATD60toD65(bool value) = 0; + // Get color appearance transform (CAT) from ACES white point to assumed observer adapted white point + virtual bool GetApplyCATD60toD65() const = 0; + + // Set reference black luminance value + virtual void SetCinemaLimitsBlack(float value) = 0; + // Get reference black luminance value + virtual float GetCinemaLimitsBlack() const = 0; + + // Set reference white luminance value + virtual void SetCinemaLimitsWhite(float value) = 0; + // Get reference white luminance value + virtual float GetCinemaLimitsWhite() const = 0; + + // Set min luminance value + virtual void SetMinPoint(float value) = 0; + // Get min luminance value + virtual float GetMinPoint() const = 0; + + // Set mid luminance value + virtual void SetMidPoint(float value) = 0; + // Get mid luminance value + virtual float GetMidPoint() const = 0; + + // Set max luminance value + virtual void SetMaxPoint(float value) = 0; + // Get max luminance value + virtual float GetMaxPoint() const = 0; + + // Set gamma adjustment value + virtual void SetSurroundGamma(float value) = 0; + // Get gamma adjustment value + virtual float GetSurroundGamma() const = 0; + + // Set optional gamma value that is applied as basic gamma curve OETF + virtual void SetGamma(float value) = 0; + // Get optional gamma value that is applied as basic gamma curve OETF + virtual float GetGamma() const = 0; }; using DisplayMapperComponentRequestBus = EBus; @@ -40,7 +99,7 @@ namespace AZ { public: //! Notifies that display mapper type changed - virtual void OntDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) + virtual void OnDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType) { } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 7831c0a4c6..06c549f560 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -10,6 +10,8 @@ * */ +#include "AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h" + #include #include @@ -32,6 +34,69 @@ namespace AZ ->Version(0) ->Field("Configuration", &DisplayMapperComponentController::m_configuration); } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("DisplayMapperComponentRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render") + // LoadPreset + ->Event("LoadPreset", &DisplayMapperComponentRequestBus::Events::LoadPreset) + // DisplayMapperOperationType + ->Event("SetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::SetDisplayMapperOperationType) + ->Event("GetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::GetDisplayMapperOperationType) + ->VirtualProperty("DisplayMapperOperationType", "GetDisplayMapperOperationType", "SetDisplayMapperOperationType") + // AcesParameterOverrides + ->Event("SetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::SetAcesParameterOverrides) + ->Event("GetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::GetAcesParameterOverrides) + ->VirtualProperty("AcesParameterOverrides", "GetAcesParameterOverrides", "SetAcesParameterOverrides") + // OverrideAcesParameters + ->Event("SetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::SetOverrideAcesParameters) + ->Event("GetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::GetOverrideAcesParameters) + ->VirtualProperty("OverrideAcesParameters", "GetOverrideAcesParameters", "SetOverrideAcesParameters") + // AlterSurround + ->Event("SetAlterSurround", &DisplayMapperComponentRequestBus::Events::SetAlterSurround) + ->Event("GetAlterSurround", &DisplayMapperComponentRequestBus::Events::GetAlterSurround) + ->VirtualProperty("AlterSurround", "GetAlterSurround", "SetAlterSurround") + // ApplyDesaturation + ->Event("SetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::SetApplyDesaturation) + ->Event("GetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::GetApplyDesaturation) + ->VirtualProperty("ApplyDesaturation", "GetApplyDesaturation", "SetApplyDesaturation") + // ApplyCATD60toD65 + ->Event("SetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::SetApplyCATD60toD65) + ->Event("GetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::GetApplyCATD60toD65) + ->VirtualProperty("ApplyCATD60toD65", "GetApplyCATD60toD65", "SetApplyCATD60toD65") + // CinemaLimitsBlack + ->Event("SetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsBlack) + ->Event("GetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsBlack) + ->VirtualProperty("CinemaLimitsBlack", "GetCinemaLimitsBlack", "SetCinemaLimitsBlack") + // CinemaLimitsWhite + ->Event("SetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsWhite) + ->Event("GetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsWhite) + ->VirtualProperty("CinemaLimitsWhite", "GetCinemaLimitsWhite", "SetCinemaLimitsWhite") + // MinPoint + ->Event("SetMinPoint", &DisplayMapperComponentRequestBus::Events::SetMinPoint) + ->Event("GetMinPoint", &DisplayMapperComponentRequestBus::Events::GetMinPoint) + ->VirtualProperty("MinPoint", "GetMinPoint", "SetMinPoint") + // MidPoint + ->Event("SetMidPoint", &DisplayMapperComponentRequestBus::Events::SetMidPoint) + ->Event("GetMidPoint", &DisplayMapperComponentRequestBus::Events::GetMidPoint) + ->VirtualProperty("MidPoint", "GetMidPoint", "SetMidPoint") + // MaxPoint + ->Event("SetMaxPoint", &DisplayMapperComponentRequestBus::Events::SetMaxPoint) + ->Event("GetMaxPoint", &DisplayMapperComponentRequestBus::Events::GetMaxPoint) + ->VirtualProperty("MaxPoint", "GetMaxPoint", "SetMaxPoint") + // SurroundGamma + ->Event("SetSurroundGamma", &DisplayMapperComponentRequestBus::Events::SetSurroundGamma) + ->Event("GetSurroundGamma", &DisplayMapperComponentRequestBus::Events::GetSurroundGamma) + ->VirtualProperty("SurroundGamma", "GetSurroundGamma", "SetSurroundGamma") + // Gamma + ->Event("SetGamma", &DisplayMapperComponentRequestBus::Events::SetGamma) + ->Event("GetGamma", &DisplayMapperComponentRequestBus::Events::GetGamma) + ->VirtualProperty("Gamma", "GetGamma", "SetGamma") + ; + } } void DisplayMapperComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) @@ -92,11 +157,16 @@ namespace AZ m_configuration.m_displayMapperOperation = displayMapperOperationType; OnConfigChanged(); DisplayMapperComponentNotificationBus::Broadcast( - &DisplayMapperComponentNotificationBus::Handler::OntDisplayMapperOperationTypeUpdated, + &DisplayMapperComponentNotificationBus::Handler::OnDisplayMapperOperationTypeUpdated, m_configuration.m_displayMapperOperation); } } + DisplayMapperOperationType DisplayMapperComponentController::GetDisplayMapperOperationType() const + { + return m_configuration.m_displayMapperOperation; + } + void DisplayMapperComponentController::SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) { m_configuration.m_acesParameterOverrides = parameterOverrides; @@ -109,6 +179,165 @@ namespace AZ m_configuration.m_acesParameterOverrides); } + const AcesParameterOverrides& DisplayMapperComponentController::GetAcesParameterOverrides() const + { + return m_configuration.m_acesParameterOverrides; + } + + void DisplayMapperComponentController::SetOverrideAcesParameters(bool value) + { + m_configuration.m_acesParameterOverrides.m_overrideDefaults = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetOverrideAcesParameters() const + { + return m_configuration.m_acesParameterOverrides.m_overrideDefaults; + } + + void DisplayMapperComponentController::SetAlterSurround(bool value) + { + m_configuration.m_acesParameterOverrides.m_alterSurround = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetAlterSurround() const + { + return m_configuration.m_acesParameterOverrides.m_alterSurround; + } + + void DisplayMapperComponentController::SetApplyDesaturation(bool value) + { + m_configuration.m_acesParameterOverrides.m_applyDesaturation = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetApplyDesaturation() const + { + return m_configuration.m_acesParameterOverrides.m_applyDesaturation; + } + + void DisplayMapperComponentController::SetApplyCATD60toD65(bool value) + { + m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + bool DisplayMapperComponentController::GetApplyCATD60toD65() const + { + return m_configuration.m_acesParameterOverrides.m_applyCATD60toD65; + } + + void DisplayMapperComponentController::SetCinemaLimitsBlack(float value) + { + m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetCinemaLimitsBlack() const + { + return m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack; + } + + void DisplayMapperComponentController::SetCinemaLimitsWhite(float value) + { + m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetCinemaLimitsWhite() const + { + return m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite; + } + + void DisplayMapperComponentController::SetMinPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_minPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMinPoint() const + { + return m_configuration.m_acesParameterOverrides.m_minPoint; + } + + void DisplayMapperComponentController::SetMidPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_midPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMidPoint() const + { + return m_configuration.m_acesParameterOverrides.m_midPoint; + } + + void DisplayMapperComponentController::SetMaxPoint(float value) + { + m_configuration.m_acesParameterOverrides.m_maxPoint = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetMaxPoint() const + { + return m_configuration.m_acesParameterOverrides.m_maxPoint; + } + + void DisplayMapperComponentController::SetSurroundGamma(float value) + { + m_configuration.m_acesParameterOverrides.m_surroundGamma = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetSurroundGamma() const + { + return m_configuration.m_acesParameterOverrides.m_surroundGamma; + } + + void DisplayMapperComponentController::SetGamma(float value) + { + m_configuration.m_acesParameterOverrides.m_gamma = value; + if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) + { + OnConfigChanged(); + } + } + + float DisplayMapperComponentController::GetGamma() const + { + return m_configuration.m_acesParameterOverrides.m_gamma; + } + void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h index efa2070828..412bdc8524 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.h @@ -51,7 +51,31 @@ namespace AZ //! DisplayMapperComponentRequestBus::Handler overrides... void LoadPreset(OutputDeviceTransformType preset) override; void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) override; + DisplayMapperOperationType GetDisplayMapperOperationType() const override; void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) override; + const AcesParameterOverrides& GetAcesParameterOverrides() const override; + void SetOverrideAcesParameters(bool value) override; + bool GetOverrideAcesParameters() const override; + void SetAlterSurround(bool value) override; + bool GetAlterSurround() const override; + void SetApplyDesaturation(bool value) override; + bool GetApplyDesaturation() const override; + void SetApplyCATD60toD65(bool value) override; + bool GetApplyCATD60toD65() const override; + void SetCinemaLimitsBlack(float value) override; + float GetCinemaLimitsBlack() const override; + void SetCinemaLimitsWhite(float value) override; + float GetCinemaLimitsWhite() const override; + void SetMinPoint(float value) override; + float GetMinPoint() const override; + void SetMidPoint(float value) override; + float GetMidPoint() const override; + void SetMaxPoint(float value) override; + float GetMaxPoint() const override; + void SetSurroundGamma(float value) override; + float GetSurroundGamma() const override; + void SetGamma(float value) override; + float GetGamma() const override; private: AZ_DISABLE_COPY(DisplayMapperComponentController); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index aadb0cc22b..4a03c6f712 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -54,63 +54,89 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + // m_overrideDefaults ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_overrideDefaults, "Override Defaults", "When enabled allows parameter overrides for ACES configuration") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_alterSurround ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_alterSurround, "Alter Surround", "Apply gamma adjustment to compensate for dim surround") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_applyDesaturation ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyDesaturation, "Alter Desaturation", "Apply desaturation to compensate for luminance difference") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_applyCATD60toD65 ->DataElement( AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyCATD60toD65, "Alter CAT D60 to D65", "Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - + + // m_cinemaLimitsBlack ->DataElement( - Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsBlack, + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsBlack, "Cinema Limit (black)", "Reference black luminance value") ->Attribute(AZ::Edit::Attributes::Min, 0.02f) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_cinemaLimitsWhite) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + + // m_cinemaLimitsWhite ->DataElement( - Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsWhite, + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsWhite, "Cinema Limit (white)", "Reference white luminance value") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_cinemaLimitsBlack) - ->Attribute(AZ::Edit::Attributes::Max, 4000) + ->Attribute(AZ::Edit::Attributes::Max, 4000.f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_minPoint ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)", "Linear extension below this") ->Attribute(AZ::Edit::Attributes::Min, 0.002f) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_midPoint) - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)", "Middle gray") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_midPoint + ->DataElement(Edit::UIHandlers::Slider, &AcesParameterOverrides::m_midPoint, + "Mid Point (luminance)", "Middle gray") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_minPoint) ->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_maxPoint) - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_maxPoint ->DataElement( - Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", + Edit::UIHandlers::Slider, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)", "Linear extension above this") ->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_midPoint) - ->Attribute(AZ::Edit::Attributes::Max, 4000) + ->Attribute(AZ::Edit::Attributes::Max, 4000.f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + + // m_surroundGamma + ->DataElement( + AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma", + "Gamma adjustment to be applied to compensate for the condition of the viewing environment") + ->Attribute(AZ::Edit::Attributes::Min, 0.6f) + ->Attribute(AZ::Edit::Attributes::Max, 1.2f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + // m_gamma ->DataElement( - AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma", - "Gamma adjustment to be applied to compensate for the condition of the viewing environment") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement( - AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_gamma, "Gamma", + AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_gamma, "Gamma", "Optional gamma value that is applied as basic gamma curve OETF") + ->Attribute(AZ::Edit::Attributes::Min, 0.2f) + ->Attribute(AZ::Edit::Attributes::Max, 4.0f) + ->Attribute(AZ::Edit::Attributes::Step, 0.005f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) // Load preset group @@ -154,6 +180,8 @@ namespace AZ if (auto behaviorContext = azrtti_cast(context)) { + behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); + behaviorContext->ConstantProperty("EditorDisplayMapperComponentTypeId", BehaviorConstant(Uuid(EditorDisplayMapperComponentTypeId))) ->Attribute(AZ::Script::Attributes::Module, "render") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation); From 3fcc1b64fce369a6129b9419187f2d78d7d39339 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Tue, 1 Jun 2021 20:24:23 -0700 Subject: [PATCH 011/153] [ATOM-15692] Ebus for registering custom feature processors for thumbnail generation --- .../ThumbnailFeatureProcessorProviderBus.h | 37 +++++++++++++++ .../Rendering/CommonThumbnailRenderer.cpp | 28 ++++++++++++ .../Rendering/CommonThumbnailRenderer.h | 11 ++++- .../ThumbnailRendererSteps/InitializeStep.cpp | 45 ++++++++++--------- 4 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h new file mode 100644 index 0000000000..71e101bcef --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h @@ -0,0 +1,37 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + namespace Thumbnails + { + //! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation + //! Duplicates will be ignored + //! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp + class ThumbnailFeatureProcessorProviderRequests + : public AZ::EBusTraits + { + public: + //! Get a list of custom feature processors to register with thumbnail renderer + virtual const AZStd::vector& GetCustomFeatureProcessors() const = 0; + }; + + using ThumbnailFeatureProcessorProviderBus = AZ::EBus; + } // namespace Thumbnails + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp index 06d54a20b3..b002a0bb66 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp @@ -34,12 +34,34 @@ namespace AZ AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type()); AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type()); SystemTickBus::Handler::BusConnect(); + ThumbnailFeatureProcessorProviderBus::Handler::BusConnect(); m_steps[Step::Initialize] = AZStd::make_shared(this); m_steps[Step::FindThumbnailToRender] = AZStd::make_shared(this); m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared(this); m_steps[Step::Capture] = AZStd::make_shared(this); m_steps[Step::ReleaseResources] = AZStd::make_shared(this); + + m_minimalFeatureProcessors = + { + "AZ::Render::TransformServiceFeatureProcessor", + "AZ::Render::MeshFeatureProcessor", + "AZ::Render::SimplePointLightFeatureProcessor", + "AZ::Render::SimpleSpotLightFeatureProcessor", + "AZ::Render::PointLightFeatureProcessor", + // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow + // flickering [ATOM-13568] + // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. + // Possibly re-enable with [GFX TODO][ATOM-13639] + // "AZ::Render::DirectionalLightFeatureProcessor", + "AZ::Render::DiskLightFeatureProcessor", + "AZ::Render::CapsuleLightFeatureProcessor", + "AZ::Render::QuadLightFeatureProcessor", + "AZ::Render::DecalTextureArrayFeatureProcessor", + "AZ::Render::ImageBasedLightFeatureProcessor", + "AZ::Render::PostProcessFeatureProcessor", + "AZ::Render::SkyBoxFeatureProcessor" + }; } CommonThumbnailRenderer::~CommonThumbnailRenderer() @@ -50,6 +72,7 @@ namespace AZ } AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); SystemTickBus::Handler::BusDisconnect(); + ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); } void CommonThumbnailRenderer::SetStep(Step step) @@ -77,6 +100,11 @@ namespace AZ AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); } + const AZStd::vector& CommonThumbnailRenderer::GetCustomFeatureProcessors() const + { + return m_minimalFeatureProcessors; + } + AZStd::shared_ptr CommonThumbnailRenderer::GetData() const { return m_data; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h index 50e73f4391..249a1f1343 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h @@ -17,6 +17,8 @@ #include #include +#include + // Disables warning messages triggered by the Qt library // 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) @@ -34,9 +36,10 @@ namespace AZ //! Provides custom rendering of material and model thumbnails class CommonThumbnailRenderer - : private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + : public ThumbnailRendererContext + , private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler , private SystemTickBus::Handler - , public ThumbnailRendererContext + , private ThumbnailFeatureProcessorProviderBus::Handler { public: AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) @@ -57,9 +60,13 @@ namespace AZ //! SystemTickBus::Handler interface overrides... void OnSystemTick() override; + //! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides... + const AZStd::vector& GetCustomFeatureProcessors() const override; + AZStd::unordered_map> m_steps; Step m_currentStep = Step::None; AZStd::shared_ptr m_data; + AZStd::vector m_minimalFeatureProcessors; }; } // namespace Thumbnails } // namespace LyIntegration diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp index 322c765f1b..c35c33017a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp @@ -11,10 +11,16 @@ */ +#include +#include + +#include + #include #include #include #include + #include #include #include @@ -23,10 +29,11 @@ #include #include #include + #include #include -#include -#include +#include + #include #include #include @@ -37,7 +44,6 @@ namespace AZ { namespace Thumbnails { - InitializeStep::InitializeStep(ThumbnailRendererContext* context) : ThumbnailRendererStep(context) { @@ -50,24 +56,23 @@ namespace AZ data->m_entityContext = AZStd::make_unique(); data->m_entityContext->InitContext(); - // Create and register a scene with minimum required feature processors + // Create and register a scene with all required feature processors RPI::SceneDescriptor sceneDesc; - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::TransformServiceFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::MeshFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SimplePointLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SimpleSpotLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::PointLightFeatureProcessor"); - // There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow flickering [ATOM-13568] - // as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now. - // Possibly re-enable with [GFX TODO][ATOM-13639] - // sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DirectionalLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DiskLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::CapsuleLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::QuadLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DecalTextureArrayFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::ImageBasedLightFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::PostProcessFeatureProcessor"); - sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SkyBoxFeatureProcessor"); + + AZ::EBusAggregateResults> results; + ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors); + + AZStd::set featureProcessorNames; + for (auto& resultCollection : results.values) + { + for (auto& featureProcessorName : resultCollection) + { + if (featureProcessorNames.emplace(featureProcessorName).second) + { + sceneDesc.m_featureProcessorNames.push_back(featureProcessorName); + } + } + } data->m_scene = RPI::Scene::CreateScene(sceneDesc); From d7ae88c17b1ce1c5c59f293a0575cee9f4ea0937 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Tue, 1 Jun 2021 20:24:52 -0700 Subject: [PATCH 012/153] Adding cmake change --- .../Code/atomlyintegration_commonfeatures_editor_files.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index e58f72a121..9072cd54f2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -10,11 +10,12 @@ # set(FILES + Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h + Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h + Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h Source/Module.cpp Source/Animation/EditorAttachmentComponent.h Source/Animation/EditorAttachmentComponent.cpp - Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h - Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h Source/EditorCommonFeaturesSystemComponent.h Source/EditorCommonFeaturesSystemComponent.cpp Source/CoreLights/EditorAreaLightComponent.h From 982c30eefdbe3364c55265e690bcec576b6a2dc6 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Tue, 1 Jun 2021 23:43:27 -0700 Subject: [PATCH 013/153] Added a visibility result flag to RPI::Cullable, set to true if the object passed all culling tests. --- .../Code/Include/Atom/RPI.Public/Culling.h | 3 +++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 25 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) 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 3f03fb9dcb..295797d2dd 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -96,6 +96,9 @@ namespace AZ }; LodData m_lodData; + //! Flag indicating if the object is visible, i.e., was not culled out in the last frame + bool m_isVisible = true; + void SetDebugName([[maybe_unused]] const AZ::Name& debugName) { #ifdef AZ_CULL_DEBUG_ENABLED diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 79d152f661..85b6bf07b8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -315,21 +315,29 @@ namespace AZ //Add all objects within this node to the view, without any extra culling for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { -#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) -#endif { if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { Cullable* c = static_cast(visibleEntry->m_userData); + + // reset visibility flag to false, update to true if all culling checks pass + c->m_isVisible = false; + if ((c->m_cullData.m_drawListMask & drawListMask).none() || c->m_cullData.m_hideFlags & viewFlags || c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this { continue; } - numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); - ++numVisibleCullables; + +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) +#endif + { + numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); + ++numVisibleCullables; + c->m_isVisible = true; + } } } } @@ -342,6 +350,10 @@ namespace AZ if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { Cullable* c = static_cast(visibleEntry->m_userData); + + // reset visibility flag to false, update to true if all culling checks pass + c->m_isVisible = false; + if ((c->m_cullData.m_drawListMask & drawListMask).none() || c->m_cullData.m_hideFlags & viewFlags || c->m_cullData.m_scene != m_jobData->m_scene) //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this @@ -362,6 +374,7 @@ namespace AZ { numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); ++numVisibleCullables; + c->m_isVisible = true; } } } @@ -461,11 +474,11 @@ namespace AZ corners[7] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); // find min clip-space depth and NDC min/max + float minDepth = FLT_MAX; float ndcMinX = FLT_MAX; float ndcMinY = FLT_MAX; float ndcMaxX = -FLT_MAX; float ndcMaxY = -FLT_MAX; - float minDepth = FLT_MAX; for (uint32_t index = 0; index < 8; ++index) { minDepth = AZStd::min(minDepth, corners[index].GetW()); From a1b8d1233cb75a330adfd260ad85c827f163f84d Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 11:28:22 -0700 Subject: [PATCH 014/153] [cpack_installer] initial work for installer Jenkins jobs --- .../build/Platform/Windows/build_config.json | 15 ++++++++ .../Windows/build_installer_windows.cmd | 22 +++++++++++ .../build/Platform/Windows/build_windows.cmd | 9 +++++ .../Platform/Windows/installer_windows.cmd | 38 +++++++++++++++++++ .../Platform/Windows/install_utiltools.ps1 | 3 ++ 5 files changed, 87 insertions(+) create mode 100644 scripts/build/Platform/Windows/build_installer_windows.cmd create mode 100644 scripts/build/Platform/Windows/installer_windows.cmd diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index 38cd7d6ad8..b0d16f1fb6 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -306,6 +306,21 @@ "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" } }, + "windows_installer": { + "TAGS": [ + "package" + ], + "COMMAND": "build_installer_windows.cmd", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build\\windows_vs2019", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE", + "CMAKE_INCLUDE_WIX": "True", + "CMAKE_LY_PROJECTS": "", + "CMAKE_TARGET": "ALL_BUILD", + "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" + } + }, "project_enginesource_profile_vs2019": { "TAGS": [ "project" diff --git a/scripts/build/Platform/Windows/build_installer_windows.cmd b/scripts/build/Platform/Windows/build_installer_windows.cmd new file mode 100644 index 0000000000..0d50f4b57a --- /dev/null +++ b/scripts/build/Platform/Windows/build_installer_windows.cmd @@ -0,0 +1,22 @@ +@ECHO OFF +REM +REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +REM its licensors. +REM +REM For complete copyright and license terms please see the LICENSE at the root of this +REM distribution (the "License"). All use of this software is governed by the License, +REM or, if provided, by the license below or the license accompanying this file. Do not +REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM + +CALL "%~dp0build_windows.cmd" +IF NOT %ERRORLEVEL%==0 GOTO :error + +CALL "%~dp0installer_windows.cmd" +IF NOT %ERRORLEVEL%==0 GOTO :error + +EXIT /b 0 + +:error +EXIT /b 1 \ No newline at end of file diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 3e995e1905..109db3438e 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,6 +38,15 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 +IF %CMAKE_INCLUDE_WIX%=="True" ( + REM Explicitly enable wix via command line arg for forensic logging + SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" +) +ELSE ( + REM Disable implicit enabling of windows packing by clearing out the wix variable + SET WIX= +) + SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS% IF NOT EXIST CMakeCache.txt ( diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd new file mode 100644 index 0000000000..c613f0a1e3 --- /dev/null +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -0,0 +1,38 @@ +@ECHO OFF +REM +REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +REM its licensors. +REM +REM For complete copyright and license terms please see the LICENSE at the root of this +REM distribution (the "License"). All use of this software is governed by the License, +REM or, if provided, by the license below or the license accompanying this file. Do not +REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM + +SETLOCAL EnableDelayedExpansion + +CALL %~dp0env_windows.cmd + +IF NOT EXIST %OUTPUT_DIRECTORY% ( + ECHO [ci_build] Error: $OUTPUT_DIRECTORY was not found + GOTO :error +) +PUSHD %OUTPUT_DIRECTORY% + +REM Override the temporary directory used by wix to the EBS volume +SET "WIX_TEMP=!WORKSPACE!/temp/wix" + +REM Run cpack +ECHO [ci_build] cpack -C %CONFIGURATION% +cpack -C %CONFIGURATION% +IF NOT %ERRORLEVEL%==0 GOTO :popd_error + +POPD +EXIT /b 0 + +:popd_error +POPD + +:error +EXIT /b 1 \ No newline at end of file diff --git a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 index 4e3695d35d..35ae04cc09 100644 --- a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 +++ b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 @@ -29,3 +29,6 @@ choco install corretto8jdk -y --ia INSTALLDIR="c:\jdk8" # Custom directory to ha # Install CMake choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System' + +# Install WIX +choco install wixtoolset -y From ee0ecc2fa03b73cb95e3987d56a63441cfc8fe0a Mon Sep 17 00:00:00 2001 From: mnaumov Date: Wed, 2 Jun 2021 11:49:08 -0700 Subject: [PATCH 015/153] [ATOM-15711] Changing thumbmail sphere to polar sphere --- Gems/Atom/Feature/Common/Assets/Models/sphere.fbx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx b/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx index 5c8f550c8c..eb02c68394 100644 --- a/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx +++ b/Gems/Atom/Feature/Common/Assets/Models/sphere.fbx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a476e99b55cf2a76fef6775c5a57dad29f8ffcb942c625bab04c89051a72a560 -size 62626 +oid sha256:838830c99f344f5b68e5e85c9bc52751350caf48e662c9c2b767ab77039bbd8f +size 103472 From cfd06f2e4a46869052dd5d6e5baee03d21860d35 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 13:10:11 -0700 Subject: [PATCH 016/153] [cpack_installer] added check for desired cmake version to be at least greater than minimum required plus minor cleanup --- cmake/Packaging.cmake | 10 ++++++++-- cmake/Platform/Windows/Packaging_windows.cmake | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 84bad13687..e7136eab12 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -51,6 +51,12 @@ if(NOT CPACK_GENERATOR) return() endif() +if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) + message(FATAL_ERROR + "The desired version of CMake to be included in the package is " + "is below the minium required version of CMake to run") +endif() + # pull down the desired copy of CMake so it can be included in the package if(NOT (CPACK_CMAKE_PACKAGE_FILE AND CPACK_CMAKE_PACKAGE_HASH)) message(FATAL_ERROR @@ -67,7 +73,7 @@ list(GET _version_componets 1 _minor_version) set(_url_version_tag "v${_major_version}.${_minor_version}") set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") -message(STATUS "Ensuring CMake ${CPACK_DESIRED_CMAKE_VERSION} is available for packaging...") +message(STATUS "Downloading CMake ${CPACK_DESIRED_CMAKE_VERSION} for packaging...") download_file( URL ${_package_url} TARGET_FILE ${_cmake_package_dest} @@ -77,7 +83,7 @@ download_file( list(GET _results 0 _status_code) if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) - message(STATUS "-> Package found and verified!") + message(STATUS "Package found and verified!") else() file(REMOVE ${_cmake_package_dest}) list(REMOVE_AT _results 0) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index db9c7fc906..5210c24e7b 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -12,7 +12,7 @@ set(LY_WIX_PATH "" CACHE PATH "Path to the WiX install path") if(LY_WIX_PATH) - file(TO_CMAKE_PATH ${LY_QTIFW_PATH} CPACK_WIX_ROOT) + file(TO_CMAKE_PATH ${LY_WIX_PATH} CPACK_WIX_ROOT) elseif(DEFINED ENV{WIX}) file(TO_CMAKE_PATH $ENV{WIX} CPACK_WIX_ROOT) endif() @@ -26,7 +26,7 @@ else() return() endif() -set(CPACK_GENERATOR "WIX") +set(CPACK_GENERATOR WIX) set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") From 12cdaed03e0c968630c4b27d25d86cdeede3c389 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 13:58:37 -0700 Subject: [PATCH 017/153] [cpack_installer] updated installer icon/logo --- cmake/Platform/Windows/Packaging/product_icon.ico | 4 ++-- cmake/Platform/Windows/Packaging/product_logo.png | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/product_icon.ico b/cmake/Platform/Windows/Packaging/product_icon.ico index 0680ceea19..e7b77c35bf 100644 --- a/cmake/Platform/Windows/Packaging/product_icon.ico +++ b/cmake/Platform/Windows/Packaging/product_icon.ico @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c042fce57915fc749abc7b37de765fd697c3c4d7de045a3d44805aa0ce29901a -size 107016 +oid sha256:d717f77fe01f45df934a61bbc215e5322447d21e16f3cebcf2a02f148178f266 +size 106449 diff --git a/cmake/Platform/Windows/Packaging/product_logo.png b/cmake/Platform/Windows/Packaging/product_logo.png index d5fd60ffb8..ac9c06f8f1 100644 --- a/cmake/Platform/Windows/Packaging/product_logo.png +++ b/cmake/Platform/Windows/Packaging/product_logo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac0348c906c91de864cba91c0231b4794d8a00fafa630d13f2232351b90aa59b +oid sha256:8c804a6be619b9f35cad46eab30b94def7a4ac7142a92cb3f7c78a659381d834 size 11074 From 4b40f23d0b63cdf5b75188000c843e08c168c139 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 14:06:27 -0700 Subject: [PATCH 018/153] [cpack_installer] couple small fixes to installer Jenkins scripts --- scripts/build/Platform/Windows/build_windows.cmd | 5 ++--- scripts/build/Platform/Windows/installer_windows.cmd | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 109db3438e..a2f42b75cf 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,11 +38,10 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 -IF %CMAKE_INCLUDE_WIX%=="True" ( +IF "%CMAKE_INCLUDE_WIX%"=="True" ( REM Explicitly enable wix via command line arg for forensic logging SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" -) -ELSE ( +) ELSE ( REM Disable implicit enabling of windows packing by clearing out the wix variable SET WIX= ) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index c613f0a1e3..e8ce10ff14 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -22,6 +22,9 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" +IF NOT EXIST "%WIX_TEMP%" ( + MKDIR %WIX_TEMP% +) REM Run cpack ECHO [ci_build] cpack -C %CONFIGURATION% From a69db3bf7681e2e6cef653919544ec3828b195c4 Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 14:44:02 -0700 Subject: [PATCH 019/153] Converts physx console commands from cry console to az console, fixes some bugs in the multiplayer gem --- .../Components/NetworkTransformComponent.cpp | 12 +++ .../Source/MultiplayerSystemComponent.cpp | 79 +++++++++++-------- .../Code/Source/SystemComponent.cpp | 49 ++++-------- Gems/PhysXDebug/Code/Source/SystemComponent.h | 3 - 4 files changed, 75 insertions(+), 68 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index 9a49724fb8..d4abf6e789 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -81,6 +81,9 @@ namespace Multiplayer void NetworkTransformComponent::OnResetCountChangedEvent() { + m_targetTransform.SetRotation(GetRotation()); + m_targetTransform.SetTranslation(GetTranslation()); + m_targetTransform.SetUniformScale(GetScale()); m_previousTransform = m_targetTransform; } @@ -93,6 +96,15 @@ namespace Multiplayer blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); blendTransform.SetScale(m_previousTransform.GetScale().Lerp(m_targetTransform.GetScale(), blendFactor)); GetTransformComponent()->SetWorldTM(blendTransform); + + //AZLOG + //( + // NET_Movement, + // "Blending entity to position %f x %f x %f", + // blendTransform.GetTranslation().GetX(), + // blendTransform.GetTranslation().GetY(), + // blendTransform.GetTranslation().GetZ() + //); } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 485a3719ad..38f0fda94e 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -634,45 +634,62 @@ namespace Multiplayer const float adjustedBlendFactor = 1.0f - (std::powf(0.2f, m_renderBlendFactor)); AZLOG(NET_Blending, "Computed blend factor of %f", adjustedBlendFactor); - AZ::Transform activeCameraTransform; - Camera::Configuration activeCameraConfiguration; - Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraTransform, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraTransform); - Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraConfiguration, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraConfiguration); - - const AZ::ViewFrustumAttributes frustumAttributes - ( - activeCameraTransform, - activeCameraConfiguration.m_frustumHeight / activeCameraConfiguration.m_frustumWidth, - activeCameraConfiguration.m_fovRadians, - activeCameraConfiguration.m_nearClipDistance, - activeCameraConfiguration.m_farClipDistance - ); - const AZ::Frustum viewFrustum = AZ::Frustum(frustumAttributes); - - // Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system - AZStd::vector gatheredEntities; - AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface::Get(); - AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum, - [&gatheredEntities, entityBoundsUnion](const AzFramework::IVisibilityScene::NodeData& nodeData) + if (Camera::ActiveCameraRequestBus::HasHandlers()) { - gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size()); - for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) + // If there's a camera, update only what's visible + AZ::Transform activeCameraTransform; + Camera::Configuration activeCameraConfiguration; + Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraTransform, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraTransform); + Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraConfiguration, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraConfiguration); + + const AZ::ViewFrustumAttributes frustumAttributes + ( + activeCameraTransform, + activeCameraConfiguration.m_frustumHeight / activeCameraConfiguration.m_frustumWidth, + activeCameraConfiguration.m_fovRadians, + activeCameraConfiguration.m_nearClipDistance, + activeCameraConfiguration.m_farClipDistance + ); + const AZ::Frustum viewFrustum = AZ::Frustum(frustumAttributes); + + // Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system + AZStd::vector gatheredEntities; + AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface::Get(); + AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum, + [&gatheredEntities, entityBoundsUnion](const AzFramework::IVisibilityScene::NodeData& nodeData) { - if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) + gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size()); + for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) { - AZ::Entity* entity = static_cast(visEntry->m_userData); - NetBindComponent* netBindComponent = entity->template FindComponent(); - if (netBindComponent != nullptr) + if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) { - gatheredEntities.push_back(netBindComponent); + AZ::Entity* entity = static_cast(visEntry->m_userData); + NetBindComponent* netBindComponent = entity->FindComponent(); + if (netBindComponent != nullptr) + { + gatheredEntities.push_back(netBindComponent); + } } } - } - }); + }); - for (NetBindComponent* netBindComponent : gatheredEntities) + for (NetBindComponent* netBindComponent : gatheredEntities) + { + netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + } + } + else { - netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + // If there's no camera, fall back to updating all net entities + for (auto& iter : *(m_networkEntityManager.GetNetworkEntityTracker())) + { + AZ::Entity* entity = iter.second; + NetBindComponent* netBindComponent = entity->FindComponent(); + if (netBindComponent != nullptr) + { + netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor); + } + } } } diff --git a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp index 08bf71753d..24a28b8f43 100644 --- a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp +++ b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -183,9 +184,7 @@ namespace PhysXDebug void SystemComponent::OnCrySystemInitialized([[maybe_unused]] ISystem& system, const SSystemInitParams&) { InitPhysXColorMappings(); - RegisterCommands(); ConfigurePhysXVisualizationParameters(); - } void SystemComponent::Reflect(AZ::ReflectContext* context) @@ -537,12 +536,13 @@ namespace PhysXDebug } } - static void CmdEnableWireFrame([[maybe_unused]] IConsoleCmdArgs* args) + static void physx_EnableWireFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { PhysXDebug::PhysXDebugRequestBus::Broadcast(&PhysXDebug::PhysXDebugRequestBus::Events::ToggleCullingWireFrame); } + AZ_CONSOLEFREEFUNC(physx_EnableWireFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Enables physx wireframe view"); - static void CmdConnectToPvd([[maybe_unused]] IConsoleCmdArgs* args) + static void physx_ConnectToPvd([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { auto* debug = AZ::Interface::Get(); if (debug) @@ -550,8 +550,9 @@ namespace PhysXDebug debug->ConnectToPvd(); } } + AZ_CONSOLEFREEFUNC(physx_ConnectToPvd, AZ::ConsoleFunctorFlags::DontReplicate, "Connects to the physx visual debugger"); - static void CmdDisconnectFromPvd([[maybe_unused]] IConsoleCmdArgs* args) + static void physx_DisconnectFromPvd([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { auto* debug = AZ::Interface::Get(); if (debug) @@ -559,13 +560,14 @@ namespace PhysXDebug debug->DisconnectFromPvd(); } } + AZ_CONSOLEFREEFUNC(physx_DisconnectFromPvd, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects from the physx visual debugger"); - static void CmdSetPhysXDebugCullingBoxSize(IConsoleCmdArgs* args) + static void physx_SetPhysXDebugCullingBoxSize([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { - const int argumentCount = args->GetArgCount(); + const int argumentCount = arguments.size(); if (argumentCount == 2) { - float newCullingBoxSize = (float)strtol(args->GetArg(1), nullptr, 10); + float newCullingBoxSize = (float)strtol(AZ::CVarFixedString(arguments[1]).c_str(), nullptr, 10); PhysXDebug::PhysXDebugRequestBus::Broadcast(&PhysXDebug::PhysXDebugRequestBus::Events::SetCullingBoxSize, newCullingBoxSize); } else @@ -574,16 +576,17 @@ namespace PhysXDebug "Please use physx_SetDebugCullingBoxSize e.g. physx_SetDebugCullingBoxSize 100."); } } + AZ_CONSOLEFREEFUNC(physx_SetPhysXDebugCullingBoxSize, AZ::ConsoleFunctorFlags::DontReplicate, "Sets physx debug culling box size"); - static void CmdTogglePhysXDebugVisualization(IConsoleCmdArgs* args) + static void physx_TogglePhysXDebugVisualization([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { using namespace CryStringUtils; - const int argumentCount = args->GetArgCount(); + const int argumentCount = arguments.size(); if (argumentCount == 2) { - const auto userPreference = static_cast(strtol(args->GetArg(1), nullptr, 10)); + const auto userPreference = static_cast(strtol(AZ::CVarFixedString(arguments[1]).c_str(), nullptr, 10)); switch (userPreference) { @@ -609,29 +612,7 @@ namespace PhysXDebug AZ_Warning("PhysXDebug", false, "Invalid physx_Debug Arguments. Please use physx_Debug 1 to enable, physx_Debug 0 to disable or physx_Debug 2 to enable all configuration settings."); } } - - void SystemComponent::RegisterCommands() - { - if (m_registered) - { - return; - } - - if (gEnv) - { - IConsole* console = gEnv->pSystem->GetIConsole(); - if (console) - { - console->AddCommand("physx_Debug", CmdTogglePhysXDebugVisualization); - console->AddCommand("physx_CullingBox", CmdEnableWireFrame); - console->AddCommand("physx_CullingBoxSize", CmdSetPhysXDebugCullingBoxSize); - console->AddCommand("physx_PvdConnect", CmdConnectToPvd); - console->AddCommand("physx_PvdDisconnect", CmdDisconnectFromPvd); - } - - m_registered = true; - } - } + AZ_CONSOLEFREEFUNC(physx_TogglePhysXDebugVisualization, AZ::ConsoleFunctorFlags::DontReplicate, "Toggles physx debug visualization"); void SystemComponent::ConfigurePhysXVisualizationParameters() { diff --git a/Gems/PhysXDebug/Code/Source/SystemComponent.h b/Gems/PhysXDebug/Code/Source/SystemComponent.h index 631354c034..f4d033fd4c 100644 --- a/Gems/PhysXDebug/Code/Source/SystemComponent.h +++ b/Gems/PhysXDebug/Code/Source/SystemComponent.h @@ -161,9 +161,6 @@ namespace PhysXDebug /// Initialise the PhysX debug draw colors based on defaults. void InitPhysXColorMappings(); - /// Register debug drawing PhysX commands with Open 3D Engine console during game mode. - void RegisterCommands(); - /// Draw the culling box being used by the viewport. /// @param cullingBoxAabb culling box Aabb to debug draw. void DrawDebugCullingBox(const AZ::Aabb& cullingBoxAabb); From 8ef2bd751821c56ed841bb15d6b9765a05d75b8a Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 14:47:05 -0700 Subject: [PATCH 020/153] Turn off desync debug by default, as this explodes network input sizes --- .../Source/Components/LocalPredictionPlayerInputComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 99e19a89fd..97e194dccb 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -25,7 +25,7 @@ namespace Multiplayer AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay"); #ifndef AZ_RELEASE_BUILD AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat"); - AZ_CVAR(bool, cl_EnableDesyncDebugging, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs"); + AZ_CVAR(bool, cl_EnableDesyncDebugging, false, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs"); #endif AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs"); From b013d7ac6780c61607792bb291627da4a08154e0 Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 14:53:33 -0700 Subject: [PATCH 021/153] Minor cleanup --- .../Components/NetworkTransformComponent.cpp | 9 --------- .../Code/Source/SystemComponent.cpp | 20 +++++++++---------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index d4abf6e789..2de838df93 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -96,15 +96,6 @@ namespace Multiplayer blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); blendTransform.SetScale(m_previousTransform.GetScale().Lerp(m_targetTransform.GetScale(), blendFactor)); GetTransformComponent()->SetWorldTM(blendTransform); - - //AZLOG - //( - // NET_Movement, - // "Blending entity to position %f x %f x %f", - // blendTransform.GetTranslation().GetX(), - // blendTransform.GetTranslation().GetY(), - // blendTransform.GetTranslation().GetZ() - //); } } diff --git a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp index 24a28b8f43..34315eb11e 100644 --- a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp +++ b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp @@ -536,13 +536,13 @@ namespace PhysXDebug } } - static void physx_EnableWireFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + static void physx_CullingBox([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { PhysXDebug::PhysXDebugRequestBus::Broadcast(&PhysXDebug::PhysXDebugRequestBus::Events::ToggleCullingWireFrame); } - AZ_CONSOLEFREEFUNC(physx_EnableWireFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Enables physx wireframe view"); + AZ_CONSOLEFREEFUNC(physx_CullingBox, AZ::ConsoleFunctorFlags::DontReplicate, "Enables physx wireframe view"); - static void physx_ConnectToPvd([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + static void physx_PvdConnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { auto* debug = AZ::Interface::Get(); if (debug) @@ -550,9 +550,9 @@ namespace PhysXDebug debug->ConnectToPvd(); } } - AZ_CONSOLEFREEFUNC(physx_ConnectToPvd, AZ::ConsoleFunctorFlags::DontReplicate, "Connects to the physx visual debugger"); + AZ_CONSOLEFREEFUNC(physx_PvdConnect, AZ::ConsoleFunctorFlags::DontReplicate, "Connects to the physx visual debugger"); - static void physx_DisconnectFromPvd([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + static void physx_PvdDisconnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { auto* debug = AZ::Interface::Get(); if (debug) @@ -560,9 +560,9 @@ namespace PhysXDebug debug->DisconnectFromPvd(); } } - AZ_CONSOLEFREEFUNC(physx_DisconnectFromPvd, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects from the physx visual debugger"); + AZ_CONSOLEFREEFUNC(physx_PvdDisconnect, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects from the physx visual debugger"); - static void physx_SetPhysXDebugCullingBoxSize([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + static void physx_CullingBoxSize([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { const int argumentCount = arguments.size(); if (argumentCount == 2) @@ -576,9 +576,9 @@ namespace PhysXDebug "Please use physx_SetDebugCullingBoxSize e.g. physx_SetDebugCullingBoxSize 100."); } } - AZ_CONSOLEFREEFUNC(physx_SetPhysXDebugCullingBoxSize, AZ::ConsoleFunctorFlags::DontReplicate, "Sets physx debug culling box size"); + AZ_CONSOLEFREEFUNC(physx_CullingBoxSize, AZ::ConsoleFunctorFlags::DontReplicate, "Sets physx debug culling box size"); - static void physx_TogglePhysXDebugVisualization([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + static void physx_Debug([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { using namespace CryStringUtils; @@ -612,7 +612,7 @@ namespace PhysXDebug AZ_Warning("PhysXDebug", false, "Invalid physx_Debug Arguments. Please use physx_Debug 1 to enable, physx_Debug 0 to disable or physx_Debug 2 to enable all configuration settings."); } } - AZ_CONSOLEFREEFUNC(physx_TogglePhysXDebugVisualization, AZ::ConsoleFunctorFlags::DontReplicate, "Toggles physx debug visualization"); + AZ_CONSOLEFREEFUNC(physx_Debug, AZ::ConsoleFunctorFlags::DontReplicate, "Toggles physx debug visualization"); void SystemComponent::ConfigurePhysXVisualizationParameters() { From c6e4e3ed1fd549d88e27a0aac254ec3ab267bc98 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 14:57:18 -0700 Subject: [PATCH 022/153] [cpack_installer] few more small fixes to installer Jenkins scripts --- scripts/build/Platform/Windows/build_windows.cmd | 2 +- scripts/build/build_node/Platform/Windows/install_utiltools.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index a2f42b75cf..799e6828b2 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -40,7 +40,7 @@ SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 IF "%CMAKE_INCLUDE_WIX%"=="True" ( REM Explicitly enable wix via command line arg for forensic logging - SET EXTRA_CMAKE_OPTIONS=%EXTRA_CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" + SET CMAKE_OPTIONS=%CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" ) ELSE ( REM Disable implicit enabling of windows packing by clearing out the wix variable SET WIX= diff --git a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 index 35ae04cc09..050e446f52 100644 --- a/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 +++ b/scripts/build/build_node/Platform/Windows/install_utiltools.ps1 @@ -30,5 +30,5 @@ choco install corretto8jdk -y --ia INSTALLDIR="c:\jdk8" # Custom directory to ha # Install CMake choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System' -# Install WIX +# Install Windows Installer XML toolkit (WiX) choco install wixtoolset -y From 134258c18acff77588b7f57d8200d069144ecc2a Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 15:03:26 -0700 Subject: [PATCH 023/153] [cpack_installer] add trailing newline to some new files --- scripts/build/Platform/Windows/build_installer_windows.cmd | 2 +- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/build_installer_windows.cmd b/scripts/build/Platform/Windows/build_installer_windows.cmd index 0d50f4b57a..4f31fee085 100644 --- a/scripts/build/Platform/Windows/build_installer_windows.cmd +++ b/scripts/build/Platform/Windows/build_installer_windows.cmd @@ -19,4 +19,4 @@ IF NOT %ERRORLEVEL%==0 GOTO :error EXIT /b 0 :error -EXIT /b 1 \ No newline at end of file +EXIT /b 1 diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index e8ce10ff14..e3a60fee1c 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -38,4 +38,4 @@ EXIT /b 0 POPD :error -EXIT /b 1 \ No newline at end of file +EXIT /b 1 From 82f9d08cfd7539482dd137e5c66d181f1ce11013 Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 15:21:43 -0700 Subject: [PATCH 024/153] Build fix for uniform scale changes --- .../Code/Source/Components/NetworkTransformComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index 2de838df93..bb256701ff 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -94,7 +94,7 @@ namespace Multiplayer AZ::Transform blendTransform; blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor)); blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor)); - blendTransform.SetScale(m_previousTransform.GetScale().Lerp(m_targetTransform.GetScale(), blendFactor)); + blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor)); GetTransformComponent()->SetWorldTM(blendTransform); } } From 38853eb2c2426dfed99be3384b2923fce5d0116e Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 15:34:35 -0700 Subject: [PATCH 025/153] Linux build fix --- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 074e9af86c..f30c8912de 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -38,6 +38,8 @@ #include +#include // for std::powf on linux + namespace AZ::ConsoleTypeHelpers { template <> From 197241f16d4a7f0ec6bfc33af715d43aff93e6e8 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 15:40:41 -0700 Subject: [PATCH 026/153] [cpack_installer] fixed issue with cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index e3a60fee1c..824a461a4b 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -26,9 +26,17 @@ IF NOT EXIST "%WIX_TEMP%" ( MKDIR %WIX_TEMP% ) +REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty +IF "%LY_CMAKE_PATH%"=="" ( + for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" + for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" +) ELSE ( + SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" +) + REM Run cpack -ECHO [ci_build] cpack -C %CONFIGURATION% -cpack -C %CONFIGURATION% +ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% +"%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From fd8cff6aecb2c93b93e6e09f9927feac563392c7 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 16:10:41 -0700 Subject: [PATCH 027/153] [cpack_installer] second attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 824a461a4b..b1fecaa2cb 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -23,10 +23,11 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( - MKDIR %WIX_TEMP% + MKDIR "WIX_TEMP%" ) REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty +SET CMAKE_INSTALL_PATH= IF "%LY_CMAKE_PATH%"=="" ( for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" @@ -34,6 +35,11 @@ IF "%LY_CMAKE_PATH%"=="" ( SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" ) +IF "%CMAKE_INSTALL_PATH%"=="" ( + ECHO [ci_build] CPack path not found + GOTO :popd_error +) + REM Run cpack ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% From c752b9d0fc19ca1f5f5cbc713184b0aeaedd1d9a Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 3 Jun 2021 01:04:01 +0100 Subject: [PATCH 028/153] Fixed ctrl+g port number. Enabled server spawn for levels with no network entities since we can spawn net entities from the scripts --- .../Editor/MultiplayerEditorConnection.cpp | 41 +++++++++++-------- .../Editor/MultiplayerEditorConnection.h | 4 +- .../MultiplayerEditorSystemComponent.cpp | 2 +- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index f684e1f12f..710a051cd9 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -109,11 +109,7 @@ namespace Multiplayer AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); - uint16_t serverPort = DefaultServerPort; - if (auto console = AZ::Interface::Get(); console) - { - console->GetCvarValue("sv_port", serverPort); - } + uint16_t serverPort = GetGameServerPort(); networkInterface->Listen(serverPort); AZLOG_INFO("Editor Server completed asset receive, responding to Editor..."); @@ -138,18 +134,20 @@ namespace Multiplayer if (auto console = AZ::Interface::Get(); console) { AZ::CVarFixedString remoteAddress; - uint16_t remotePort; - if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && - console->GetCvarValue("editorsv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) - { - // Connect the Editor to the editor server for Multiplayer simulation - AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); - INetworkInterface* networkInterface = - AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); + uint16_t remotePort = GetGameServerPort(); + if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound) + { + // Connect the Editor to the editor server for Multiplayer simulation + AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); + INetworkInterface* networkInterface = + AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); - const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType()); - networkInterface->Connect(ipAddress); - } + // Connecting to DefaultServerPort here + const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType()); + networkInterface->Connect(ipAddress); + + AZ::Interface::Get()->SendReadyForEntityUpdates(true); + } } } return true; @@ -184,4 +182,15 @@ namespace Multiplayer { ; } + + uint16_t MultiplayerEditorConnection::GetGameServerPort() + { + uint16_t serverPort = DefaultServerPort; + if (auto console = AZ::Interface::Get(); console) + { + console->GetCvarValue("sv_port", serverPort); + } + return serverPort; + } + } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index d803a60744..aeafc09861 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -39,7 +39,8 @@ namespace Multiplayer bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet); - + + //! IConnectionListener interface //! @{ AzNetworking::ConnectResult ValidateConnect(const AzNetworking::IpAddress& remoteAddress, const AzNetworking::IPacketHeader& packetHeader, AzNetworking::ISerializer& serializer) override; @@ -50,6 +51,7 @@ namespace Multiplayer //! @} private: + uint16_t GetGameServerPort(); AzNetworking::INetworkInterface* m_networkEditorInterface = nullptr; AZStd::vector m_buffer; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 523ffd90de..3ac4e98d42 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -165,7 +165,7 @@ namespace Multiplayer // BeginGameMode and Prefab Processing have completed at this point IMultiplayerTools* mpTools = AZ::Interface::Get(); - if (editorsv_enabled && mpTools != nullptr && mpTools->DidProcessNetworkPrefabs()) + if (editorsv_enabled && mpTools != nullptr) { const AZStd::vector>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData(); From 3b519c64756df01777dc89b134308338794a4e72 Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 3 Jun 2021 01:06:15 +0100 Subject: [PATCH 029/153] removed whitespace --- .../Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index aeafc09861..40eb38af1d 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -40,7 +40,6 @@ namespace Multiplayer bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet); - //! IConnectionListener interface //! @{ AzNetworking::ConnectResult ValidateConnect(const AzNetworking::IpAddress& remoteAddress, const AzNetworking::IPacketHeader& packetHeader, AzNetworking::ISerializer& serializer) override; From bffb7d1b2876633780c728969906c656f813105e Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 3 Jun 2021 01:20:22 +0100 Subject: [PATCH 030/153] Simplified the change to rely on sv_port cvar --- .../Editor/MultiplayerEditorConnection.cpp | 41 ++++++++----------- .../Editor/MultiplayerEditorConnection.h | 3 +- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 710a051cd9..847d1caadf 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -109,7 +109,11 @@ namespace Multiplayer AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); - uint16_t serverPort = GetGameServerPort(); + uint16_t serverPort = DefaultServerPort; + if (auto console = AZ::Interface::Get(); console) + { + console->GetCvarValue("sv_port", serverPort); + } networkInterface->Listen(serverPort); AZLOG_INFO("Editor Server completed asset receive, responding to Editor..."); @@ -134,20 +138,20 @@ namespace Multiplayer if (auto console = AZ::Interface::Get(); console) { AZ::CVarFixedString remoteAddress; - uint16_t remotePort = GetGameServerPort(); - if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound) - { - // Connect the Editor to the editor server for Multiplayer simulation - AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); - INetworkInterface* networkInterface = - AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); + uint16_t remotePort; + if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && + console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) + { + // Connect the Editor to the editor server for Multiplayer simulation + AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::Client); + INetworkInterface* networkInterface = + AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MPNetworkInterfaceName)); - // Connecting to DefaultServerPort here - const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType()); - networkInterface->Connect(ipAddress); + const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType()); + networkInterface->Connect(ipAddress); - AZ::Interface::Get()->SendReadyForEntityUpdates(true); - } + AZ::Interface::Get()->SendReadyForEntityUpdates(true); + } } } return true; @@ -182,15 +186,4 @@ namespace Multiplayer { ; } - - uint16_t MultiplayerEditorConnection::GetGameServerPort() - { - uint16_t serverPort = DefaultServerPort; - if (auto console = AZ::Interface::Get(); console) - { - console->GetCvarValue("sv_port", serverPort); - } - return serverPort; - } - } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index 40eb38af1d..d803a60744 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -39,7 +39,7 @@ namespace Multiplayer bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet); - + //! IConnectionListener interface //! @{ AzNetworking::ConnectResult ValidateConnect(const AzNetworking::IpAddress& remoteAddress, const AzNetworking::IPacketHeader& packetHeader, AzNetworking::ISerializer& serializer) override; @@ -50,7 +50,6 @@ namespace Multiplayer //! @} private: - uint16_t GetGameServerPort(); AzNetworking::INetworkInterface* m_networkEditorInterface = nullptr; AZStd::vector m_buffer; From e445c643211322d9c4193669200ebc1965bc777e Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 3 Jun 2021 01:21:27 +0100 Subject: [PATCH 031/153] Fixed TimedThread bled %d ms logging to not spam the console --- .../AzNetworking/AzNetworking/Utilities/TimedThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp index d078149996..7e1f41f745 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp @@ -46,7 +46,7 @@ namespace AzNetworking } else if (m_updateRate < updateTimeMs) { - AZLOG_INFO("TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); + AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate)); } } OnStop(); From 201d6b1b72ec579c980c5e38d58fc354bfcc9a29 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 17:29:50 -0700 Subject: [PATCH 032/153] [cpack_installer] third attempt to fix cpack selection --- .../Platform/Windows/installer_windows.cmd | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index b1fecaa2cb..41cc21b35b 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -26,23 +26,29 @@ IF NOT EXIST "%WIX_TEMP%" ( MKDIR "WIX_TEMP%" ) -REM Make sure we are using the CMake version of CPack and not the one that comes with chocolaty -SET CMAKE_INSTALL_PATH= +REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey +SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( - for /f %%i in ('where cmake') do SET "CMAKE_EXE_PATH=%%i" - for %%F in ("%CMAKE_EXE_PATH%") do SET "CMAKE_INSTALL_PATH=%%~dpF" + FOR /F %%i in ('where cpack') DO ( + REM The cpack in chocolatey expects a number supplied with --version so it will error + %%i --version > NUL + IF !ERRORLEVEL!==0 ( + SET "CPACK_PATH=%%i" + ) + ) ) ELSE ( - SET "CMAKE_INSTALL_PATH=%LY_CMAKE_PATH%\" + SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) -IF "%CMAKE_INSTALL_PATH%"=="" ( - ECHO [ci_build] CPack path not found - GOTO :popd_error +ECHO [ci_build] "%CPACK_PATH%" --version +"%CPACK_PATH%" --version +IF ERRORLEVEL 1 ( + ECHO [ci_build] CPack not found! + exit /b 1 ) - REM Run cpack -ECHO [ci_build] "%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% -"%CMAKE_INSTALL_PATH%cpack" -C %CONFIGURATION% +ECHO [ci_build] "%CPACK_PATH%" -C %CONFIGURATION% +"%CPACK_PATH%" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From 01f3ba560819fcba0d3a5575510e597904cced4f Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 17:58:58 -0700 Subject: [PATCH 033/153] [cpack_installer] fourth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 41cc21b35b..ef284290f3 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -23,7 +23,7 @@ PUSHD %OUTPUT_DIRECTORY% REM Override the temporary directory used by wix to the EBS volume SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( - MKDIR "WIX_TEMP%" + MKDIR "%WIX_TEMP%" ) REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey @@ -40,15 +40,15 @@ IF "%LY_CMAKE_PATH%"=="" ( SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) -ECHO [ci_build] "%CPACK_PATH%" --version -"%CPACK_PATH%" --version +ECHO [ci_build] "!CPACK_PATH!" --version +"!CPACK_PATH!" --version IF ERRORLEVEL 1 ( ECHO [ci_build] CPack not found! exit /b 1 ) -REM Run cpack -ECHO [ci_build] "%CPACK_PATH%" -C %CONFIGURATION% -"%CPACK_PATH%" -C %CONFIGURATION% + +ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% +"!CPACK_PATH!" -C %CONFIGURATION% IF NOT %ERRORLEVEL%==0 GOTO :popd_error POPD From 9dbe596e400bbeac8fcecc34227821fceab378b1 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 18:39:05 -0700 Subject: [PATCH 034/153] Added reflection probe cubemap quality levels --- .../Config/IBLSpecular.preset | 15 +- .../Config/IBLSpecularHigh.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularLow.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularVeryHigh.preset | 135 ++++++++++++++++++ .../Config/IBLSpecularVeryLow.preset | 135 ++++++++++++++++++ .../EditorReflectionProbeComponent.cpp | 20 ++- .../EditorReflectionProbeComponent.h | 1 + .../ReflectionProbeComponentController.cpp | 1 + .../ReflectionProbeComponentController.h | 24 ++++ 9 files changed, 595 insertions(+), 6 deletions(-) create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset index d940f425c2..4f935c73ff 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset @@ -8,7 +8,8 @@ "Name": "IBLSpecular", "Description": "The input cubemap generates an IBL specular output cubemap.", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -34,7 +35,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -59,7 +61,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -84,7 +87,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", @@ -109,7 +113,8 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "FileMasks": [ - "_iblspecularcm" + "_iblspecularcm", + "_iblspecularcm256" ], "SourceColor": "Linear", "DestColor": "Linear", diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset new file mode 100644 index 0000000000..ff4e143326 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", + "Name": "IBLSpecularHigh", + "FileMasks": [ + "_iblspecularcm512" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 512, + "MaxTextureSize": 512, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset new file mode 100644 index 0000000000..ee9ddd6ac7 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", + "Name": "IBLSpecularLow", + "FileMasks": [ + "_iblspecularcm128" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 128, + "MaxTextureSize": 128, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset new file mode 100644 index 0000000000..08d9416935 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", + "Name": "IBLSpecularVeryHigh", + "FileMasks": [ + "_iblspecularcm1024" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 1024, + "MaxTextureSize": 1024, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset new file mode 100644 index 0000000000..c5c0788848 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset @@ -0,0 +1,135 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "Description": "The input cubemap generates an IBL specular output cubemap.", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", + "Name": "IBLSpecularVeryLow", + "FileMasks": [ + "_iblspecularcm64" + ], + "SourceColor": "Linear", + "DestColor": "Linear", + "SuppressEngineReduce": true, + "PixelFormat": "R9G9B9E5", + "DiscardAlpha": true, + "MinTextureSize": 64, + "MaxTextureSize": 64, + "IsPowerOf2": true, + "CubemapSettings": { + "Filter": "GGX", + "MipAngle": 7.0, + "MipSlope": 2.299999952316284, + "EdgeFixup": -431602080.0, + "SubId": 2000 + }, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index 7880d5e88c..f3932322b1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -39,6 +39,7 @@ namespace AZ serializeContext->Class() ->Version(2, ConvertToEditorRenderComponentAdapter<1>) ->Field("useBakedCubemap", &EditorReflectionProbeComponent::m_useBakedCubemap) + ->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel) ->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath) ->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset) ; @@ -67,6 +68,13 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap") ->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorReflectionProbeComponent::OnUseBakedCubemapValidate) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnUseBakedCubemapChanged) + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel, "Baked Cubemap Quality", "Resolution of the baked cubemap") + ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) + ->EnumAttribute(BakedCubeMapQualityLevel::VeryLow, "Very Low") + ->EnumAttribute(BakedCubeMapQualityLevel::Low, "Low") + ->EnumAttribute(BakedCubeMapQualityLevel::Medium, "Medium") + ->EnumAttribute(BakedCubeMapQualityLevel::High, "High") + ->EnumAttribute(BakedCubeMapQualityLevel::VeryHigh, "Very High") ->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath, "Baked Cubemap Path", "Baked Cubemap Path") ->Attribute(AZ::Edit::Attributes::ReadOnly, true) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) @@ -332,6 +340,12 @@ namespace AZ // clear it to force the generation of a new filename cubeMapRelativePath.clear(); } + + // if the quality level changed we need to generate a new filename + if (m_controller.m_configuration.m_bakedCubeMapQualityLevel != m_bakedCubeMapQualityLevel) + { + cubeMapRelativePath.clear(); + } } // build a new cubemap path if necessary @@ -345,7 +359,10 @@ namespace AZ AZStd::string uuidString; uuid.ToString(uuidString); - cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + "_iblspecularcm.dds"; + // determine the filemask suffix from the cubemap quality level setting + AZStd::string fileSuffix = BakedCubeMapFileSuffixes[aznumeric_cast(m_bakedCubeMapQualityLevel)]; + + cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + fileSuffix; // replace any invalid filename characters auto invalidCharacters = [](char letter) @@ -384,6 +401,7 @@ namespace AZ // save the relative source path in the configuration AzToolsFramework::ScopedUndoBatch undoBatch("Cubemap path changed."); m_controller.m_configuration.m_bakedCubeMapRelativePath = cubeMapRelativePath; + m_controller.m_configuration.m_bakedCubeMapQualityLevel = m_bakedCubeMapQualityLevel; SetDirty(); // update UI cubemap path display diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h index 23fd391818..bc45eae11b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h @@ -77,6 +77,7 @@ namespace AZ // UI settings // the user can select between a baked cubemap or an authored cubemap asset bool m_useBakedCubemap = true; + BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium; AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 9b0ff29bb8..873810c016 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -46,6 +46,7 @@ namespace AZ ->Field("InnerLength", &ReflectionProbeComponentConfig::m_innerLength) ->Field("InnerWidth", &ReflectionProbeComponentConfig::m_innerWidth) ->Field("UseBakedCubemap", &ReflectionProbeComponentConfig::m_useBakedCubemap) + ->Field("BakedCubemapQualityLevel", &ReflectionProbeComponentConfig::m_bakedCubeMapQualityLevel) ->Field("BakedCubeMapRelativePath", &ReflectionProbeComponentConfig::m_bakedCubeMapRelativePath) ->Field("BakedCubeMapAsset", &ReflectionProbeComponentConfig::m_bakedCubeMapAsset) ->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h index 0a57fde882..97a7fbebb4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h @@ -24,6 +24,29 @@ namespace AZ { namespace Render { + enum class BakedCubeMapQualityLevel : uint32_t + { + VeryLow, // 64 + Low, // 128 + Medium, // 256 + High, // 512 + VeryHigh, // 1024 + + Count + }; + + static const char* BakedCubeMapFileSuffixes[] = + { + "_iblspecularcm64.dds", + "_iblspecularcm128.dds", + "_iblspecularcm256.dds", + "_iblspecularcm512.dds", + "_iblspecularcm1024.dds" + }; + + static_assert(AZ_ARRAY_SIZE(BakedCubeMapFileSuffixes) == aznumeric_cast(BakedCubeMapQualityLevel::Count), + "BakedCubeMapFileSuffixes must have the same number of entries as BakedCubeMapQualityLevel"); + class ReflectionProbeComponentConfig final : public AZ::ComponentConfig { @@ -43,6 +66,7 @@ namespace AZ bool m_showVisualization = true; bool m_useBakedCubemap = true; + BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium; AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; From 3f9811e498efdb07e9275a3395f201b65ce8aa0f Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 18:40:22 -0700 Subject: [PATCH 035/153] [cpack_installer] fifth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index ef284290f3..73d1a3d88c 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -31,7 +31,7 @@ SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( FOR /F %%i in ('where cpack') DO ( REM The cpack in chocolatey expects a number supplied with --version so it will error - %%i --version > NUL + "%%i" --version > NUL IF !ERRORLEVEL!==0 ( SET "CPACK_PATH=%%i" ) From c3df73bed8f4b052659086e69127e90ae794bb46 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Wed, 2 Jun 2021 18:48:50 -0700 Subject: [PATCH 036/153] PR feedback and fixing TrackView --- .../DisplayMapperConfigurationDescriptor.cpp | 2 +- .../DisplayMapper/DisplayMapperComponentBus.h | 5 +++++ .../DisplayMapperComponentController.cpp | 20 +++++++++++++++++++ .../EditorDisplayMapperComponent.cpp | 5 ++--- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp index 0858381fc5..a064b61a1a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperConfigurationDescriptor.cpp @@ -96,7 +96,7 @@ namespace AZ ; serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("Name", &DisplayMapperConfigurationDescriptor::m_name) ->Field("OperationType", &DisplayMapperConfigurationDescriptor::m_operationType) ->Field("LdrGradingLutEnabled", &DisplayMapperConfigurationDescriptor::m_ldrGradingLutEnabled) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h index 4a01f71325..448c6cd32a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h @@ -26,6 +26,11 @@ namespace AZ : public ComponentBus { public: + AZ_RTTI(AZ::Render::DisplayMapperComponentRequests, "{9E2E8AF5-1176-44B4-A461-E09867753349}"); + + /// Overrides the default AZ::EBusTraits handler policy to allow one listener only. + static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single; + //! Load preconfigured preset for specific ODT mode virtual void LoadPreset(OutputDeviceTransformType preset) = 0; //! Set display mapper type diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index 06c549f560..30c0ac8b1d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -122,10 +122,14 @@ namespace AZ void DisplayMapperComponentController::Activate(EntityId entityId) { m_entityId = entityId; + + DisplayMapperComponentRequestBus::Handler::BusConnect(m_entityId); } void DisplayMapperComponentController::Deactivate() { + DisplayMapperComponentRequestBus::Handler::BusDisconnect(m_entityId); + m_postProcessInterface = nullptr; m_entityId.SetInvalid(); } @@ -186,6 +190,10 @@ namespace AZ void DisplayMapperComponentController::SetOverrideAcesParameters(bool value) { + if (m_configuration.m_acesParameterOverrides.m_overrideDefaults == value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_overrideDefaults = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -200,6 +208,10 @@ namespace AZ void DisplayMapperComponentController::SetAlterSurround(bool value) { + if (m_configuration.m_acesParameterOverrides.m_alterSurround != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_alterSurround = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -214,6 +226,10 @@ namespace AZ void DisplayMapperComponentController::SetApplyDesaturation(bool value) { + if (m_configuration.m_acesParameterOverrides.m_applyDesaturation != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_applyDesaturation = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { @@ -228,6 +244,10 @@ namespace AZ void DisplayMapperComponentController::SetApplyCATD60toD65(bool value) { + if (m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 != value) + { + return; // prevents flickering when set via TrackView + } m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 = value; if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp index 4a03c6f712..8b59cfc9ea 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/EditorDisplayMapperComponent.cpp @@ -10,10 +10,9 @@ * */ -#include "Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h" - #include #include +#include namespace AZ { @@ -180,7 +179,7 @@ namespace AZ if (auto behaviorContext = azrtti_cast(context)) { - behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); + behaviorContext->Class()->RequestBus("DisplayMapperComponentRequestBus"); behaviorContext->ConstantProperty("EditorDisplayMapperComponentTypeId", BehaviorConstant(Uuid(EditorDisplayMapperComponentTypeId))) ->Attribute(AZ::Script::Attributes::Module, "render") From 35fed7722305c8a3eaadb91f45836628d5d2ba33 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Wed, 2 Jun 2021 21:56:03 -0400 Subject: [PATCH 037/153] Adding CLI script for modifying project properties (LYN-3918). Updating O3de to support it. Fixing some typo errors in manifest.py and minor optimizations --- scripts/o3de.py | 7 ++- scripts/o3de/o3de/manifest.py | 12 +--- scripts/o3de/o3de/project_properties.py | 82 +++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 scripts/o3de/o3de/project_properties.py diff --git a/scripts/o3de.py b/scripts/o3de.py index 8d7532878c..85d49ec268 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -32,7 +32,7 @@ def add_args(parser, subparsers) -> None: # add the scripts/o3de directory to the front of the sys.path sys.path.insert(0, str(o3de_package_dir)) from o3de import engine_template, global_project, register, print_registration, get_registration, \ - enable_gem, disable_gem, sha256 + enable_gem, disable_gem, project_properties, sha256 # Remove the temporarily added path sys.path = sys.path[1:] @@ -55,7 +55,10 @@ def add_args(parser, subparsers) -> None: # remove a gem from a project disable_gem.add_args(subparsers) - + + # modify project properties + project_properties.add_args(subparsers) + # sha256 sha256.add_args(subparsers) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 2a7e5bba11..edcd44c525 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -573,9 +573,7 @@ def get_registered(engine_name: str = None, return engine_path elif isinstance(project_name, str): - enging_projects = get_engine_projects() - projects = json_data['projects'].copy() - projects.extend(engine_object['projects']) + projects = get_all_projects() for project_path in projects: project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' @@ -605,9 +603,7 @@ def get_registered(engine_name: str = None, return gem_path elif isinstance(template_name, str): - engine_templates = get_engine_templates() - templates = json_data['templates'].copy() - templates.extend(engine_templates) + templates = get_all_templates() for template_path in templates: template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' @@ -622,9 +618,7 @@ def get_registered(engine_name: str = None, return template_path elif isinstance(restricted_name, str): - engine_restricted = get_engine_restricted() - restricted = json_data['restricted'].copy() - restricted.extend(engine_restricted) + restricted = get_all_restricted() for restricted_path in restricted: restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py new file mode 100644 index 0000000000..10153ff833 --- /dev/null +++ b/scripts/o3de/o3de/project_properties.py @@ -0,0 +1,82 @@ +import argparse +import json +import os +import pathlib +import sys +import logging + +from o3de import manifest + +logger = logging.getLogger() +logging.basicConfig() + +def get_project_props(name: str = None, path: pathlib.Path = None) -> dict: + proj_json = manifest.get_project_json_data(project_name=name, project_path=path) + if not proj_json: + logger.error('Could not retrieve project.json file') + return None + return proj_json + +def edit_project_props(proj_path, proj_name, new_origin, new_display, + new_summary, new_icon, new_tag) -> int: + proj_json = get_project_props(proj_name, proj_path) + + try: + if new_origin and 'origin' in proj_json: + proj_json['origin'] = new_origin + if new_display and 'display_name' in proj_json: + proj_json['display_name'] = new_display + if new_summary and 'summary' in proj_json: + proj_json['summary'] = new_summary + if new_icon and 'icon_path' in proj_json: + proj_json['icon_path'] = new_icon + if new_tag and 'user_tags' in proj_json: + proj_json['user_tags'].append(new_tag) + except Exception as e: + logger.error(e) + return 1 + + manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path)/'project.json') + return 0 + +def _edit_project_props(args: argparse) -> int: + return edit_project_props(args.project_path, + args.project_name, + args.project_origin, + args.project_display, + args.project_summary, + args.project_icon, + args.project_tag) + +def add_parser_args(parser): + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False, + help='The path to the project.') + group.add_argument('-pn', '--project-name', type=str, required=False, + help='The name of the project.') + group = parser.add_argument_group('properties', 'arguments for modifying individual project properties.') + group.add_argument('-po', '--project-origin', type=str, required=False, + help='Sets description or url for project origin.') + group.add_argument('-pd', '--project-display', type=str, required=False, + help='Sets the project display name.') + group.add_argument('-ps', '--project-summary', type=str, required=False, + help='Sets the summary description of the project.') + group.add_argument('-pi', '--project-icon', type=str, required=False, + help='Sets the path to the projects icon resource.') + group.add_argument('-pt', '--project-tag', type=str, required=False, + help='Adds a tag to canonical user tags.') + parser.set_defaults(func=_edit_project_props) + +def add_args(subparsers) -> None: + enable_project_props_subparser = subparsers.add_parser('edit-project-props') + add_parser_args(enable_project_props_subparser) + +def main(): + the_parser = argparse.ArgumentParser() + add_parser_args(the_parser) + the_args = the_parser.parse_args() + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + sys.exit(ret) + +if __name__ == "__main__": + main() \ No newline at end of file From 86234841689b7c48de57b3d7b9c3a60f129637a0 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 19:02:42 -0700 Subject: [PATCH 038/153] Added Masked Occlusion Culling external files --- .../CompilerSpecific.inl | 98 + .../MaskedOcclusionCulling/LICENSE.txt | 181 ++ .../MaskedOcclusionCulling.cpp | 456 ++++ .../MaskedOcclusionCulling.h | 592 +++++ .../MaskedOcclusionCullingAVX2.cpp | 243 ++ .../MaskedOcclusionCullingAVX512.cpp | 309 +++ .../MaskedOcclusionCullingCommon.inl | 2053 +++++++++++++++++ .../MaskedOcclusionCulling/PackageInfo.json | 6 + 8 files changed, 3938 insertions(+) create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/CompilerSpecific.inl create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/LICENSE.txt create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingCommon.inl create mode 100644 Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/PackageInfo.json diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/CompilerSpecific.inl b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/CompilerSpecific.inl new file mode 100644 index 0000000000..a6203ff939 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/CompilerSpecific.inl @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common shared include file to hide compiler/os specific functions from the rest of the code. +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) + #define __MICROSOFT_COMPILER +#endif + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__clang__)) // Windows: MSVC / Intel compiler / clang + #include + #include + + #define FORCE_INLINE __forceinline + + FORCE_INLINE unsigned long find_clear_lsb(unsigned int *mask) + { + unsigned long idx; + _BitScanForward(&idx, *mask); + *mask &= *mask - 1; + return idx; + } + + FORCE_INLINE void *aligned_alloc(size_t alignment, size_t size) + { + return _aligned_malloc(size, alignment); + } + + FORCE_INLINE void aligned_free(void *ptr) + { + _aligned_free(ptr); + } + +#elif defined(__GNUG__) || defined(__clang__) // G++ or clang + #include +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) + #include // memalign +#else + #include // memalign +#endif + #include + #include + #include + + #define FORCE_INLINE inline + + FORCE_INLINE unsigned long find_clear_lsb(unsigned int *mask) + { + unsigned long idx; + idx = __builtin_ctzl(*mask); + *mask &= *mask - 1; + return idx; + } + + FORCE_INLINE void *aligned_alloc(size_t alignment, size_t size) + { + return memalign(alignment, size); + } + + FORCE_INLINE void aligned_free(void *ptr) + { + free(ptr); + } + + FORCE_INLINE void __cpuidex(int* cpuinfo, int function, int subfunction) + { + __cpuid_count(function, subfunction, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); + } + + FORCE_INLINE unsigned long long _xgetbv(unsigned int index) + { + unsigned int eax, edx; + __asm__ __volatile__( + "xgetbv;" + : "=a" (eax), "=d"(edx) + : "c" (index) + ); + return ((unsigned long long)edx << 32) | eax; + } + +#else + #error Unsupported compiler +#endif diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/LICENSE.txt b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/LICENSE.txt new file mode 100644 index 0000000000..f1b08a582c --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/LICENSE.txt @@ -0,0 +1,181 @@ + +Apache License + Version 2.0, January 2004 + + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable copyright license to +reproduce, prepare Derivative Works of, publicly display, publicly perform, +sublicense, and distribute the Work and such Derivative Works in Source or +Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise +transfer the Work, where such license applies only to those patent claims +licensable by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) with the Work +to which such Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim in a lawsuit) +alleging that the Work or a Contribution incorporated within the Work +constitutes direct or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate as of the date +such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and in +Source or Object form, provided that You meet the following conditions: + You must give any other recipients of the Work or Derivative Works a copy of + this License; and + + + You must cause any modified files to carry prominent notices stating that You + changed the files; and + + + You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from the + Source form of the Work, excluding those notices that do not pertain to any + part of the Derivative Works; and + + + If the Work includes a "NOTICE" text file as part of its distribution, then + any Derivative Works that You distribute must include a readable copy of the + attribution notices contained within such NOTICE file, excluding those notices + that do not pertain to any part of the Derivative Works, in at least one of + the following places: within a NOTICE text file distributed as part of the + Derivative Works; within the Source form or documentation, if provided along + with the Derivative Works; or, within a display generated by the Derivative + Works, if and wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative Works that + You distribute, alongside or as an addendum to the NOTICE text from the Work, + provided that such additional attribution notices cannot be construed as + modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any +additional terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may have +executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in +writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in +tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to in +writing, shall any Contributor be liable to You for damages, including any +direct, indirect, special, incidental, or consequential damages of any character +arising as a result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, work stoppage, +computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such +damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such +obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred +by, or claims asserted against, such Contributor by reason of your accepting any +such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + +Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, +Version 2.0 (the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or +agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp new file mode 100644 index 0000000000..2844fbde00 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.cpp @@ -0,0 +1,456 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include "MaskedOcclusionCulling.h" +#include "CompilerSpecific.inl" + +#if MOC_RECORDER_ENABLE +#include "FrameRecorder.h" +#endif + +#if defined(__AVX__) || defined(__AVX2__) + // For performance reasons, the MaskedOcclusionCullingAVX2/512.cpp files should be compiled with VEX encoding for SSE instructions (to avoid + // AVX-SSE transition penalties, see https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties). However, this file + // _must_ be compiled without VEX encoding to allow backwards compatibility. Best practice is to use lowest supported target platform + // (/arch:SSE2) as project default, and elevate only the MaskedOcclusionCullingAVX2/512.cpp files. + #error The MaskedOcclusionCulling.cpp should be compiled with lowest supported target platform, e.g. /arch:SSE2 +#endif + +static MaskedOcclusionCulling::Implementation DetectCPUFeatures(MaskedOcclusionCulling::pfnAlignedAlloc alignedAlloc, MaskedOcclusionCulling::pfnAlignedFree alignedFree) +{ + struct CpuInfo { int regs[4]; }; + + // Get regular CPUID values + int regs[4]; + __cpuidex(regs, 0, 0); + + // MOCVectorAllocator mocalloc( alignedAlloc, alignedFree ); + // std::vector> cpuId( mocalloc ), cpuIdEx( mocalloc ); + // cpuId.resize( regs[0] ); + size_t cpuIdCount = regs[0]; + CpuInfo * cpuId = (CpuInfo*)alignedAlloc( 64, sizeof(CpuInfo) * cpuIdCount ); + + for (size_t i = 0; i < cpuIdCount; ++i) + __cpuidex(cpuId[i].regs, (int)i, 0); + + // Get extended CPUID values + __cpuidex(regs, 0x80000000, 0); + + //cpuIdEx.resize(regs[0] - 0x80000000); + size_t cpuIdExCount = regs[0] - 0x80000000; + CpuInfo * cpuIdEx = (CpuInfo*)alignedAlloc( 64, sizeof( CpuInfo ) * cpuIdExCount ); + + for (size_t i = 0; i < cpuIdExCount; ++i) + __cpuidex(cpuIdEx[i].regs, 0x80000000 + (int)i, 0); + + #define TEST_BITS(A, B) (((A) & (B)) == (B)) + #define TEST_FMA_MOVE_OXSAVE (cpuIdCount >= 1 && TEST_BITS(cpuId[1].regs[2], (1 << 12) | (1 << 22) | (1 << 27))) + #define TEST_LZCNT (cpuIdExCount >= 1 && TEST_BITS(cpuIdEx[1].regs[2], 0x20)) + #define TEST_SSE41 (cpuIdCount >= 1 && TEST_BITS(cpuId[1].regs[2], (1 << 19))) + #define TEST_XMM_YMM (cpuIdCount >= 1 && TEST_BITS(_xgetbv(0), (1 << 2) | (1 << 1))) + #define TEST_OPMASK_ZMM (cpuIdCount >= 1 && TEST_BITS(_xgetbv(0), (1 << 7) | (1 << 6) | (1 << 5))) + #define TEST_BMI1_BMI2_AVX2 (cpuIdCount >= 7 && TEST_BITS(cpuId[7].regs[1], (1 << 3) | (1 << 5) | (1 << 8))) + #define TEST_AVX512_F_BW_DQ (cpuIdCount >= 7 && TEST_BITS(cpuId[7].regs[1], (1 << 16) | (1 << 17) | (1 << 30))) + + MaskedOcclusionCulling::Implementation retVal = MaskedOcclusionCulling::SSE2; + if (TEST_FMA_MOVE_OXSAVE && TEST_LZCNT && TEST_SSE41) + { + if (TEST_XMM_YMM && TEST_OPMASK_ZMM && TEST_BMI1_BMI2_AVX2 && TEST_AVX512_F_BW_DQ) + retVal = MaskedOcclusionCulling::AVX512; + else if (TEST_XMM_YMM && TEST_BMI1_BMI2_AVX2) + retVal = MaskedOcclusionCulling::AVX2; + } + else if (TEST_SSE41) + retVal = MaskedOcclusionCulling::SSE41; + alignedFree( cpuId ); + alignedFree( cpuIdEx ); + return retVal; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Utility functions (not directly related to the algorithm/rasterizer) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void MaskedOcclusionCulling::TransformVertices(const float *mtx, const float *inVtx, float *xfVtx, unsigned int nVtx, const VertexLayout &vtxLayout) +{ + // This function pretty slow, about 10-20% slower than if the vertices are stored in aligned SOA form. + if (nVtx == 0) + return; + + // Load matrix and swizzle out the z component. For post-multiplication (OGL), the matrix is assumed to be column + // major, with one column per SSE register. For pre-multiplication (DX), the matrix is assumed to be row major. + __m128 mtxCol0 = _mm_loadu_ps(mtx); + __m128 mtxCol1 = _mm_loadu_ps(mtx + 4); + __m128 mtxCol2 = _mm_loadu_ps(mtx + 8); + __m128 mtxCol3 = _mm_loadu_ps(mtx + 12); + + int stride = vtxLayout.mStride; + const char *vPtr = (const char *)inVtx; + float *outPtr = xfVtx; + + // Iterate through all vertices and transform + for (unsigned int vtx = 0; vtx < nVtx; ++vtx) + { + __m128 xVal = _mm_load1_ps((float*)(vPtr)); + __m128 yVal = _mm_load1_ps((float*)(vPtr + vtxLayout.mOffsetY)); + __m128 zVal = _mm_load1_ps((float*)(vPtr + vtxLayout.mOffsetZ)); + + __m128 xform = _mm_add_ps(_mm_mul_ps(mtxCol0, xVal), _mm_add_ps(_mm_mul_ps(mtxCol1, yVal), _mm_add_ps(_mm_mul_ps(mtxCol2, zVal), mtxCol3))); + _mm_storeu_ps(outPtr, xform); + vPtr += stride; + outPtr += 4; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Typedefs +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef MaskedOcclusionCulling::pfnAlignedAlloc pfnAlignedAlloc; +typedef MaskedOcclusionCulling::pfnAlignedFree pfnAlignedFree; +typedef MaskedOcclusionCulling::VertexLayout VertexLayout; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common SSE2/SSE4.1 defines +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SIMD_LANES 4 +#define TILE_HEIGHT_SHIFT 2 + +#define SIMD_LANE_IDX _mm_setr_epi32(0, 1, 2, 3) + +#define SIMD_SUB_TILE_COL_OFFSET _mm_setr_epi32(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET _mm_setzero_si128() +#define SIMD_SUB_TILE_COL_OFFSET_F _mm_setr_ps(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET_F _mm_setzero_ps() + +#define SIMD_LANE_YCOORD_I _mm_setr_epi32(128, 384, 640, 896) +#define SIMD_LANE_YCOORD_F _mm_setr_ps(128.0f, 384.0f, 640.0f, 896.0f) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common SSE2/SSE4.1 functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef __m128 __mw; +typedef __m128i __mwi; + +#define _mmw_set1_ps _mm_set1_ps +#define _mmw_setzero_ps _mm_setzero_ps +#define _mmw_and_ps _mm_and_ps +#define _mmw_or_ps _mm_or_ps +#define _mmw_xor_ps _mm_xor_ps +#define _mmw_not_ps(a) _mm_xor_ps((a), _mm_castsi128_ps(_mm_set1_epi32(~0))) +#define _mmw_andnot_ps _mm_andnot_ps +#define _mmw_neg_ps(a) _mm_xor_ps((a), _mm_set1_ps(-0.0f)) +#define _mmw_abs_ps(a) _mm_and_ps((a), _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF))) +#define _mmw_add_ps _mm_add_ps +#define _mmw_sub_ps _mm_sub_ps +#define _mmw_mul_ps _mm_mul_ps +#define _mmw_div_ps _mm_div_ps +#define _mmw_min_ps _mm_min_ps +#define _mmw_max_ps _mm_max_ps +#define _mmw_movemask_ps _mm_movemask_ps +#define _mmw_cmpge_ps(a,b) _mm_cmpge_ps(a, b) +#define _mmw_cmpgt_ps(a,b) _mm_cmpgt_ps(a, b) +#define _mmw_cmpeq_ps(a,b) _mm_cmpeq_ps(a, b) +#define _mmw_fmadd_ps(a,b,c) _mm_add_ps(_mm_mul_ps(a,b), c) +#define _mmw_fmsub_ps(a,b,c) _mm_sub_ps(_mm_mul_ps(a,b), c) +#define _mmw_shuffle_ps _mm_shuffle_ps +#define _mmw_insertf32x4_ps(a,b,c) (b) +#define _mmw_cvtepi32_ps _mm_cvtepi32_ps +#define _mmw_blendv_epi32(a,b,c) simd_cast<__mwi>(_mmw_blendv_ps(simd_cast<__mw>(a), simd_cast<__mw>(b), simd_cast<__mw>(c))) + +#define _mmw_set1_epi32 _mm_set1_epi32 +#define _mmw_setzero_epi32 _mm_setzero_si128 +#define _mmw_and_epi32 _mm_and_si128 +#define _mmw_or_epi32 _mm_or_si128 +#define _mmw_xor_epi32 _mm_xor_si128 +#define _mmw_not_epi32(a) _mm_xor_si128((a), _mm_set1_epi32(~0)) +#define _mmw_andnot_epi32 _mm_andnot_si128 +#define _mmw_neg_epi32(a) _mm_sub_epi32(_mm_set1_epi32(0), (a)) +#define _mmw_add_epi32 _mm_add_epi32 +#define _mmw_sub_epi32 _mm_sub_epi32 +#define _mmw_subs_epu16 _mm_subs_epu16 +#define _mmw_cmpeq_epi32 _mm_cmpeq_epi32 +#define _mmw_cmpgt_epi32 _mm_cmpgt_epi32 +#define _mmw_srai_epi32 _mm_srai_epi32 +#define _mmw_srli_epi32 _mm_srli_epi32 +#define _mmw_slli_epi32 _mm_slli_epi32 +#define _mmw_cvtps_epi32 _mm_cvtps_epi32 +#define _mmw_cvttps_epi32 _mm_cvttps_epi32 + +#define _mmx_fmadd_ps _mmw_fmadd_ps +#define _mmx_max_epi32 _mmw_max_epi32 +#define _mmx_min_epi32 _mmw_min_epi32 + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SIMD casting functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template FORCE_INLINE T simd_cast(Y A); +template<> FORCE_INLINE __m128 simd_cast<__m128>(float A) { return _mm_set1_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128i A) { return _mm_castsi128_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128 A) { return A; } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(int A) { return _mm_set1_epi32(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128 A) { return _mm_castps_si128(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128i A) { return A; } + +#define MAKE_ACCESSOR(name, simd_type, base_type, is_const, elements) \ + FORCE_INLINE is_const base_type * name(is_const simd_type &a) { \ + union accessor { simd_type m_native; base_type m_array[elements]; }; \ + is_const accessor *acs = reinterpret_cast(&a); \ + return acs->m_array; \ + } + +MAKE_ACCESSOR(simd_f32, __m128, float, , 4) +MAKE_ACCESSOR(simd_f32, __m128, float, const, 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, , 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, const, 4) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Specialized SSE input assembly function for general vertex gather +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +FORCE_INLINE void GatherVertices(__m128 *vtxX, __m128 *vtxY, __m128 *vtxW, const float *inVtx, const unsigned int *inTrisPtr, int numLanes, const VertexLayout &vtxLayout) +{ + for (int lane = 0; lane < numLanes; lane++) + { + for (int i = 0; i < 3; i++) + { + char *vPtrX = (char *)inVtx + inTrisPtr[lane * 3 + i] * vtxLayout.mStride; + char *vPtrY = vPtrX + vtxLayout.mOffsetY; + char *vPtrW = vPtrX + vtxLayout.mOffsetW; + + simd_f32(vtxX[i])[lane] = *((float*)vPtrX); + simd_f32(vtxY[i])[lane] = *((float*)vPtrY); + simd_f32(vtxW[i])[lane] = *((float*)vPtrW); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SSE4.1 version +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace MaskedOcclusionCullingSSE41 +{ + FORCE_INLINE __m128i _mmw_mullo_epi32(const __m128i &a, const __m128i &b) { return _mm_mullo_epi32(a, b); } + FORCE_INLINE __m128i _mmw_min_epi32(const __m128i &a, const __m128i &b) { return _mm_min_epi32(a, b); } + FORCE_INLINE __m128i _mmw_max_epi32(const __m128i &a, const __m128i &b) { return _mm_max_epi32(a, b); } + FORCE_INLINE __m128i _mmw_abs_epi32(const __m128i &a) { return _mm_abs_epi32(a); } + FORCE_INLINE __m128 _mmw_blendv_ps(const __m128 &a, const __m128 &b, const __m128 &c) { return _mm_blendv_ps(a, b, c); } + FORCE_INLINE int _mmw_testz_epi32(const __m128i &a, const __m128i &b) { return _mm_testz_si128(a, b); } + FORCE_INLINE __m128 _mmx_dp4_ps(const __m128 &a, const __m128 &b) { return _mm_dp_ps(a, b, 0xFF); } + FORCE_INLINE __m128 _mmw_floor_ps(const __m128 &a) { return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); } + FORCE_INLINE __m128 _mmw_ceil_ps(const __m128 &a) { return _mm_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); } + FORCE_INLINE __m128i _mmw_transpose_epi8(const __m128i &a) + { + const __m128i shuff = _mm_setr_epi8(0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF); + return _mm_shuffle_epi8(a, shuff); + } + FORCE_INLINE __m128i _mmw_sllv_ones(const __m128i &ishift) + { + __m128i shift = _mm_min_epi32(ishift, _mm_set1_epi32(32)); + + // Uses lookup tables and _mm_shuffle_epi8 to perform _mm_sllv_epi32(~0, shift) + const __m128i byteShiftLUT = _mm_setr_epi8((char)0xFF, (char)0xFE, (char)0xFC, (char)0xF8, (char)0xF0, (char)0xE0, (char)0xC0, (char)0x80, 0, 0, 0, 0, 0, 0, 0, 0); + const __m128i byteShiftOffset = _mm_setr_epi8(0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24); + const __m128i byteShiftShuffle = _mm_setr_epi8(0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0xC, 0xC, 0xC, 0xC); + + __m128i byteShift = _mm_shuffle_epi8(shift, byteShiftShuffle); + byteShift = _mm_min_epi8(_mm_subs_epu8(byteShift, byteShiftOffset), _mm_set1_epi8(8)); + __m128i retMask = _mm_shuffle_epi8(byteShiftLUT, byteShift); + + return retMask; + } + + static MaskedOcclusionCulling::Implementation gInstructionSet = MaskedOcclusionCulling::SSE41; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Include common algorithm implementation (general, SIMD independent code) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #include "MaskedOcclusionCullingCommon.inl" + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Utility function to create a new object using the allocator callbacks + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + MaskedOcclusionCullingPrivate *object = (MaskedOcclusionCullingPrivate *)alignedAlloc(64, sizeof(MaskedOcclusionCullingPrivate)); + new (object) MaskedOcclusionCullingPrivate(alignedAlloc, alignedFree); + return object; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SSE2 version +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace MaskedOcclusionCullingSSE2 +{ + FORCE_INLINE __m128i _mmw_mullo_epi32(const __m128i &a, const __m128i &b) + { + // Do products for even / odd lanes & merge the result + __m128i even = _mm_and_si128(_mm_mul_epu32(a, b), _mm_setr_epi32(~0, 0, ~0, 0)); + __m128i odd = _mm_slli_epi64(_mm_mul_epu32(_mm_srli_epi64(a, 32), _mm_srli_epi64(b, 32)), 32); + return _mm_or_si128(even, odd); + } + FORCE_INLINE __m128i _mmw_min_epi32(const __m128i &a, const __m128i &b) + { + __m128i cond = _mm_cmpgt_epi32(a, b); + return _mm_or_si128(_mm_andnot_si128(cond, a), _mm_and_si128(cond, b)); + } + FORCE_INLINE __m128i _mmw_max_epi32(const __m128i &a, const __m128i &b) + { + __m128i cond = _mm_cmpgt_epi32(b, a); + return _mm_or_si128(_mm_andnot_si128(cond, a), _mm_and_si128(cond, b)); + } + FORCE_INLINE __m128i _mmw_abs_epi32(const __m128i &a) + { + __m128i mask = _mm_cmplt_epi32(a, _mm_setzero_si128()); + return _mm_add_epi32(_mm_xor_si128(a, mask), _mm_srli_epi32(mask, 31)); + } + FORCE_INLINE int _mmw_testz_epi32(const __m128i &a, const __m128i &b) + { + return _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_and_si128(a, b), _mm_setzero_si128())) == 0xFFFF; + } + FORCE_INLINE __m128 _mmw_blendv_ps(const __m128 &a, const __m128 &b, const __m128 &c) + { + __m128 cond = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(c), 31)); + return _mm_or_ps(_mm_andnot_ps(cond, a), _mm_and_ps(cond, b)); + } + FORCE_INLINE __m128 _mmx_dp4_ps(const __m128 &a, const __m128 &b) + { + // Product and two shuffle/adds pairs (similar to hadd_ps) + __m128 prod = _mm_mul_ps(a, b); + __m128 dp = _mm_add_ps(prod, _mm_shuffle_ps(prod, prod, _MM_SHUFFLE(2, 3, 0, 1))); + dp = _mm_add_ps(dp, _mm_shuffle_ps(dp, dp, _MM_SHUFFLE(0, 1, 2, 3))); + return dp; + } + FORCE_INLINE __m128 _mmw_floor_ps(const __m128 &a) + { + int originalMode = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE(_MM_ROUND_DOWN); + __m128 rounded = _mm_cvtepi32_ps(_mm_cvtps_epi32(a)); + _MM_SET_ROUNDING_MODE(originalMode); + return rounded; + } + FORCE_INLINE __m128 _mmw_ceil_ps(const __m128 &a) + { + int originalMode = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE(_MM_ROUND_UP); + __m128 rounded = _mm_cvtepi32_ps(_mm_cvtps_epi32(a)); + _MM_SET_ROUNDING_MODE(originalMode); + return rounded; + } + FORCE_INLINE __m128i _mmw_transpose_epi8(const __m128i &a) + { + // Perform transpose through two 16->8 bit pack and byte shifts + __m128i res = a; + const __m128i mask = _mm_setr_epi8(~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0, ~0, 0); + res = _mm_packus_epi16(_mm_and_si128(res, mask), _mm_srli_epi16(res, 8)); + res = _mm_packus_epi16(_mm_and_si128(res, mask), _mm_srli_epi16(res, 8)); + return res; + } + FORCE_INLINE __m128i _mmw_sllv_ones(const __m128i &ishift) + { + __m128i shift = _mmw_min_epi32(ishift, _mm_set1_epi32(32)); + + // Uses scalar approach to perform _mm_sllv_epi32(~0, shift) + static const unsigned int maskLUT[33] = { + ~0U << 0, ~0U << 1, ~0U << 2 , ~0U << 3, ~0U << 4, ~0U << 5, ~0U << 6 , ~0U << 7, ~0U << 8, ~0U << 9, ~0U << 10 , ~0U << 11, ~0U << 12, ~0U << 13, ~0U << 14 , ~0U << 15, + ~0U << 16, ~0U << 17, ~0U << 18 , ~0U << 19, ~0U << 20, ~0U << 21, ~0U << 22 , ~0U << 23, ~0U << 24, ~0U << 25, ~0U << 26 , ~0U << 27, ~0U << 28, ~0U << 29, ~0U << 30 , ~0U << 31, + 0U }; + + __m128i retMask; + simd_i32(retMask)[0] = (int)maskLUT[simd_i32(shift)[0]]; + simd_i32(retMask)[1] = (int)maskLUT[simd_i32(shift)[1]]; + simd_i32(retMask)[2] = (int)maskLUT[simd_i32(shift)[2]]; + simd_i32(retMask)[3] = (int)maskLUT[simd_i32(shift)[3]]; + return retMask; + } + + static MaskedOcclusionCulling::Implementation gInstructionSet = MaskedOcclusionCulling::SSE2; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Include common algorithm implementation (general, SIMD independent code) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #include "MaskedOcclusionCullingCommon.inl" + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Utility function to create a new object using the allocator callbacks + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + MaskedOcclusionCullingPrivate *object = (MaskedOcclusionCullingPrivate *)alignedAlloc(64, sizeof(MaskedOcclusionCullingPrivate)); + new (object) MaskedOcclusionCullingPrivate(alignedAlloc, alignedFree); + return object; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Object construction and allocation +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +namespace MaskedOcclusionCullingAVX512 +{ + extern MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree); +} + +namespace MaskedOcclusionCullingAVX2 +{ + extern MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree); +} + +MaskedOcclusionCulling *MaskedOcclusionCulling::Create(Implementation RequestedSIMD) +{ + return Create(RequestedSIMD, aligned_alloc, aligned_free); +} + +MaskedOcclusionCulling *MaskedOcclusionCulling::Create(Implementation RequestedSIMD, pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) +{ + MaskedOcclusionCulling *object = nullptr; + + MaskedOcclusionCulling::Implementation impl = DetectCPUFeatures(alignedAlloc, alignedFree); + + if (RequestedSIMD < impl) + impl = RequestedSIMD; + + // Return best supported version + if (object == nullptr && impl >= AVX512) + object = MaskedOcclusionCullingAVX512::CreateMaskedOcclusionCulling(alignedAlloc, alignedFree); // Use AVX512 version + if (object == nullptr && impl >= AVX2) + object = MaskedOcclusionCullingAVX2::CreateMaskedOcclusionCulling(alignedAlloc, alignedFree); // Use AVX2 version + if (object == nullptr && impl >= SSE41) + object = MaskedOcclusionCullingSSE41::CreateMaskedOcclusionCulling(alignedAlloc, alignedFree); // Use SSE4.1 version + if (object == nullptr) + object = MaskedOcclusionCullingSSE2::CreateMaskedOcclusionCulling(alignedAlloc, alignedFree); // Use SSE2 (slow) version + + return object; +} + +void MaskedOcclusionCulling::Destroy(MaskedOcclusionCulling *moc) +{ + pfnAlignedFree alignedFreeCallback = moc->mAlignedFreeCallback; + moc->~MaskedOcclusionCulling(); + alignedFreeCallback(moc); +} diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h new file mode 100644 index 0000000000..4ace525887 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCulling.h @@ -0,0 +1,592 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +/*! + * \file MaskedOcclusionCulling.h + * \brief Masked Occlusion Culling + * + * General information + * - Input to all API functions are (x,y,w) clip-space coordinates (x positive left, y positive up, w positive away from camera). + * We entirely skip the z component and instead compute it as 1 / w, see next bullet. For TestRect the input is NDC (x/w, y/w). + * - We use a simple z = 1 / w transform, which is a bit faster than OGL/DX depth transforms. Thus, depth is REVERSED and z = 0 at + * the far plane and z = inf at w = 0. We also have to use a GREATER depth function, which explains why all the conservative + * tests will be reversed compared to what you might be used to (for example zMaxTri >= zMinBuffer is a visibility test) + * - We support different layouts for vertex data (basic AoS and SoA), but note that it's beneficial to store the position data + * as tightly in memory as possible to reduce cache misses. Big strides are bad, so it's beneficial to keep position as a separate + * stream (rather than bundled with attributes) or to keep a copy of the position data for the occlusion culling system. + * - The resolution width must be a multiple of 8 and height a multiple of 4. + * - The hierarchical Z buffer is stored OpenGL-style with the y axis pointing up. This includes the scissor box. + * - This code is only tested with Visual Studio 2015, but should hopefully be easy to port to other compilers. + */ + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Defines used to configure the implementation +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef QUICK_MASK +/*! + * Configure the algorithm used for updating and merging hierarchical z buffer entries. If QUICK_MASK + * is defined to 1, use the algorithm from the paper "Masked Software Occlusion Culling", which has good + * balance between performance and low leakage. If QUICK_MASK is defined to 0, use the algorithm from + * "Masked Depth Culling for Graphics Hardware" which has less leakage, but also lower performance. + */ +#define QUICK_MASK 1 + +#endif + +#ifndef USE_D3D +/*! + * Configures the library for use with Direct3D (default) or OpenGL rendering. This changes whether the + * screen space Y axis points downwards (D3D) or upwards (OGL), and is primarily important in combination + * with the PRECISE_COVERAGE define, where this is important to ensure correct rounding and tie-breaker + * behaviour. It also affects the ScissorRect screen space coordinates. + */ +#define USE_D3D 1 + +#endif + +#ifndef PRECISE_COVERAGE +/*! + * Define PRECISE_COVERAGE to 1 to more closely match GPU rasterization rules. The increased precision comes + * at a cost of slightly lower performance. + */ +#define PRECISE_COVERAGE 1 + +#endif + +#ifndef USE_AVX512 +/*! + * Define USE_AVX512 to 1 to enable experimental AVX-512 support. It's currently mostly untested and only + * validated on simple examples using Intel SDE. Older compilers may not support AVX-512 intrinsics. + */ +#define USE_AVX512 0 + +#endif + +#ifndef CLIPPING_PRESERVES_ORDER +/*! + * Define CLIPPING_PRESERVES_ORDER to 1 to prevent clipping from reordering triangle rasterization + * order; This comes at a cost (approx 3-4%) but removes one source of temporal frame-to-frame instability. + */ +#define CLIPPING_PRESERVES_ORDER 1 + +#endif + +#ifndef ENABLE_STATS +/*! + * Define ENABLE_STATS to 1 to gather various statistics during occlusion culling. Can be used for profiling + * and debugging. Note that enabling this function will reduce performance significantly. + */ +#define ENABLE_STATS 0 + +#endif + +#ifndef MOC_RECORDER_ENABLE +/*! + * Define MOC_RECORDER_ENABLE to 1 to enable frame recorder (see FrameRecorder.h/cpp for details) + */ +#define MOC_RECORDER_ENABLE 0 + +#endif + +#if MOC_RECORDER_ENABLE +#ifndef MOC_RECORDER_ENABLE_PLAYBACK +/*! + * Define MOC_RECORDER_ENABLE_PLAYBACK to 1 to enable compilation of the playback code (not needed + for recording) + */ +#define MOC_RECORDER_ENABLE_PLAYBACK 0 +#endif +#endif + + +#if MOC_RECORDER_ENABLE + +#include + +class FrameRecorder; + +#endif // #if MOC_RECORDER_ENABLE + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Masked occlusion culling class +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MaskedOcclusionCulling +{ +public: + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Memory management callback functions + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + typedef void *(*pfnAlignedAlloc)(size_t alignment, size_t size); + typedef void (*pfnAlignedFree) (void *ptr); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Enums + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + enum Implementation + { + SSE2 = 0, + SSE41 = 1, + AVX2 = 2, + AVX512 = 3 + }; + + enum BackfaceWinding + { + BACKFACE_NONE = 0, + BACKFACE_CW = 1, + BACKFACE_CCW = 2, + }; + + enum CullingResult + { + VISIBLE = 0x0, + OCCLUDED = 0x1, + VIEW_CULLED = 0x3 + }; + + enum ClipPlanes + { + CLIP_PLANE_NONE = 0x00, + CLIP_PLANE_NEAR = 0x01, + CLIP_PLANE_LEFT = 0x02, + CLIP_PLANE_RIGHT = 0x04, + CLIP_PLANE_BOTTOM = 0x08, + CLIP_PLANE_TOP = 0x10, + CLIP_PLANE_SIDES = (CLIP_PLANE_LEFT | CLIP_PLANE_RIGHT | CLIP_PLANE_BOTTOM | CLIP_PLANE_TOP), + CLIP_PLANE_ALL = (CLIP_PLANE_LEFT | CLIP_PLANE_RIGHT | CLIP_PLANE_BOTTOM | CLIP_PLANE_TOP | CLIP_PLANE_NEAR) + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Structs + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /*! + * Used to specify custom vertex layout. Memory offsets to y and z coordinates are set through + * mOffsetY and mOffsetW, and vertex stride is given by mStride. It's possible to configure both + * AoS and SoA layouts. Note that large strides may cause more cache misses and decrease + * performance. It is advisable to store position data as compactly in memory as possible. + */ + struct VertexLayout + { + VertexLayout() {} + VertexLayout(int stride, int offsetY, int offsetZW) : + mStride(stride), mOffsetY(offsetY), mOffsetW(offsetZW) {} + + int mStride; //!< byte stride between vertices + int mOffsetY; //!< byte offset from X to Y coordinate + union { + int mOffsetZ; //!< byte offset from X to Z coordinate + int mOffsetW; //!< byte offset from X to W coordinate + }; + }; + + /*! + * Used to control scissoring during rasterization. Note that we only provide coarse scissor support. + * The scissor box x coordinates must be a multiple of 32, and the y coordinates a multiple of 8. + * Scissoring is mainly meant as a means of enabling binning (sort middle) rasterizers in case + * application developers want to use that approach for multithreading. + */ + struct ScissorRect + { + ScissorRect() {} + ScissorRect(int minX, int minY, int maxX, int maxY) : + mMinX(minX), mMinY(minY), mMaxX(maxX), mMaxY(maxY) {} + + int mMinX; //!< Screen space X coordinate for left side of scissor rect, inclusive and must be a multiple of 32 + int mMinY; //!< Screen space Y coordinate for bottom side of scissor rect, inclusive and must be a multiple of 8 + int mMaxX; //!< Screen space X coordinate for right side of scissor rect, non inclusive and must be a multiple of 32 + int mMaxY; //!< Screen space Y coordinate for top side of scissor rect, non inclusive and must be a multiple of 8 + }; + + /*! + * Used to specify storage area for a binlist, containing triangles. This struct is used for binning + * and multithreading. The host application is responsible for allocating memory for the binlists. + */ + struct TriList + { + unsigned int mNumTriangles; //!< Maximum number of triangles that may be stored in mPtr + unsigned int mTriIdx; //!< Index of next triangle to be written, clear before calling BinTriangles to start from the beginning of the list + float *mPtr; //!< Scratchpad buffer allocated by the host application + }; + + /*! + * Statistics that can be gathered during occluder rendering and visibility to aid debugging + * and profiling. Must be enabled by changing the ENABLE_STATS define. + */ + struct OcclusionCullingStatistics + { + struct + { + long long mNumProcessedTriangles; //!< Number of occluder triangles processed in total + long long mNumRasterizedTriangles; //!< Number of occluder triangles passing view frustum and backface culling + long long mNumTilesTraversed; //!< Number of tiles traversed by the rasterizer + long long mNumTilesUpdated; //!< Number of tiles where the hierarchical z buffer was updated + long long mNumTilesMerged; //!< Number of tiles where the hierarchical z buffer was updated + } mOccluders; + + struct + { + long long mNumProcessedRectangles; //!< Number of rects processed (TestRect()) + long long mNumProcessedTriangles; //!< Number of ocludee triangles processed (TestTriangles()) + long long mNumRasterizedTriangles; //!< Number of ocludee triangle passing view frustum and backface culling + long long mNumTilesTraversed; //!< Number of tiles traversed by triangle & rect rasterizers + } mOccludees; + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Functions + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /*! + * \brief Creates a new object with default state, no z buffer attached/allocated. + */ + static MaskedOcclusionCulling *Create(Implementation RequestedSIMD = AVX512); + + /*! + * \brief Creates a new object with default state, no z buffer attached/allocated. + * \param alignedAlloc Pointer to a callback function used when allocating memory + * \param alignedFree Pointer to a callback function used when freeing memory + */ + static MaskedOcclusionCulling *Create(Implementation RequestedSIMD, pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree); + + /*! + * \brief Destroys an object and frees the z buffer memory. Note that you cannot + * use the delete operator, and should rather use this function to free up memory. + */ + static void Destroy(MaskedOcclusionCulling *moc); + + /*! + * \brief Sets the resolution of the hierarchical depth buffer. This function will + * re-allocate the current depth buffer (if present). The contents of the + * buffer is undefined until ClearBuffer() is called. + * + * \param witdh The width of the buffer in pixels, must be a multiple of 8 + * \param height The height of the buffer in pixels, must be a multiple of 4 + */ + virtual void SetResolution(unsigned int width, unsigned int height) = 0; + + /*! + * \brief Gets the resolution of the hierarchical depth buffer. + * + * \param witdh Output: The width of the buffer in pixels + * \param height Output: The height of the buffer in pixels + */ + virtual void GetResolution(unsigned int &width, unsigned int &height) const = 0; + + /*! + * \brief Returns the tile size for the current implementation. + * + * \param nBinsW Number of vertical bins, the screen is divided into nBinsW x nBinsH + * rectangular bins. + * \param nBinsH Number of horizontal bins, the screen is divided into nBinsW x nBinsH + * rectangular bins. + * \param outBinWidth Output: The width of the single bin in pixels (except for the + * rightmost bin width, which is extended to resolution width) + * \param outBinHeight Output: The height of the single bin in pixels (except for the + * bottommost bin height, which is extended to resolution height) + */ + virtual void ComputeBinWidthHeight(unsigned int nBinsW, unsigned int nBinsH, unsigned int & outBinWidth, unsigned int & outBinHeight) = 0; + + /*! + * \brief Sets the distance for the near clipping plane. Default is nearDist = 0. + * + * \param nearDist The distance to the near clipping plane, given as clip space w + */ + virtual void SetNearClipPlane(float nearDist) = 0; + + /*! + * \brief Gets the distance for the near clipping plane. + */ + virtual float GetNearClipPlane() const = 0; + + /*! + * \brief Clears the hierarchical depth buffer. + */ + virtual void ClearBuffer() = 0; + + /*! + * \brief Merge a second hierarchical depth buffer into the main buffer. + */ + virtual void MergeBuffer(MaskedOcclusionCulling* BufferB) = 0; + + /*! + * \brief Renders a mesh of occluder triangles and updates the hierarchical z buffer + * with conservative depth values. + * + * This function is optimized for vertex layouts with stride 16 and y and w + * offsets of 4 and 12 bytes, respectively. + * + * \param inVtx Pointer to an array of input vertices, should point to the x component + * of the first vertex. The input vertices are given as (x,y,w) coordinates + * in clip space. The memory layout can be changed using vtxLayout. + * \param inTris Pointer to an array of vertex indices. Each triangle is created + * from three indices consecutively fetched from the array. + * \param nTris The number of triangles to render (inTris must contain atleast 3*nTris + * entries) + * \param modelToClipMatrix all vertices will be transformed by this matrix before + * performing projection. If nullptr is passed the transform step will be skipped + * \param bfWinding Sets triangle winding order to consider backfacing, must be one one + * of (BACKFACE_NONE, BACKFACE_CW and BACKFACE_CCW). Back-facing triangles are culled + * and will not be rasterized. You may use BACKFACE_NONE to disable culling for + * double sided geometry + * \param clipPlaneMask A mask indicating which clip planes should be considered by the + * triangle clipper. Can be used as an optimization if your application can + * determine (for example during culling) that a group of triangles does not + * intersect a certain frustum plane. However, setting an incorrect mask may + * cause out of bounds memory accesses. + * \param vtxLayout A struct specifying the vertex layout (see struct for detailed + * description). For best performance, it is advisable to store position data + * as compactly in memory as possible. + * \return Will return VIEW_CULLED if all triangles are either outside the frustum or + * backface culled, returns VISIBLE otherwise. + */ + virtual CullingResult RenderTriangles(const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix = nullptr, BackfaceWinding bfWinding = BACKFACE_CW, ClipPlanes clipPlaneMask = CLIP_PLANE_ALL, const VertexLayout &vtxLayout = VertexLayout(16, 4, 12)) = 0; + + /*! + * \brief Occlusion query for a rectangle with a given depth. The rectangle is given + * in normalized device coordinates where (x,y) coordinates between [-1,1] map + * to the visible screen area. The query uses a GREATER_EQUAL (reversed) depth + * test meaning that depth values equal to the contents of the depth buffer are + * counted as visible. + * + * \param xmin NDC coordinate of the left side of the rectangle. + * \param ymin NDC coordinate of the bottom side of the rectangle. + * \param xmax NDC coordinate of the right side of the rectangle. + * \param ymax NDC coordinate of the top side of the rectangle. + * \param ymax NDC coordinate of the top side of the rectangle. + * \param wmin Clip space W coordinate for the rectangle. + * \return The query will return VISIBLE if the rectangle may be visible, OCCLUDED + * if the rectangle is occluded by a previously rendered object, or VIEW_CULLED + * if the rectangle is outside the view frustum. + */ + virtual CullingResult TestRect(float xmin, float ymin, float xmax, float ymax, float wmin) const = 0; + + /*! + * \brief This function is similar to RenderTriangles(), but performs an occlusion + * query instead and does not update the hierarchical z buffer. The query uses + * a GREATER_EQUAL (reversed) depth test meaning that depth values equal to the + * contents of the depth buffer are counted as visible. + * + * This function is optimized for vertex layouts with stride 16 and y and w + * offsets of 4 and 12 bytes, respectively. + * + * \param inVtx Pointer to an array of input vertices, should point to the x component + * of the first vertex. The input vertices are given as (x,y,w) coordinates + * in clip space. The memory layout can be changed using vtxLayout. + * \param inTris Pointer to an array of triangle indices. Each triangle is created + * from three indices consecutively fetched from the array. + * \param nTris The number of triangles to render (inTris must contain atleast 3*nTris + * entries) + * \param modelToClipMatrix all vertices will be transformed by this matrix before + * performing projection. If nullptr is passed the transform step will be skipped + * \param bfWinding Sets triangle winding order to consider backfacing, must be one one + * of (BACKFACE_NONE, BACKFACE_CW and BACKFACE_CCW). Back-facing triangles are culled + * and will not be occlusion tested. You may use BACKFACE_NONE to disable culling + * for double sided geometry + * \param clipPlaneMask A mask indicating which clip planes should be considered by the + * triangle clipper. Can be used as an optimization if your application can + * determine (for example during culling) that a group of triangles does not + * intersect a certain frustum plane. However, setting an incorrect mask may + * cause out of bounds memory accesses. + * \param vtxLayout A struct specifying the vertex layout (see struct for detailed + * description). For best performance, it is advisable to store position data + * as compactly in memory as possible. + * \return The query will return VISIBLE if the triangle mesh may be visible, OCCLUDED + * if the mesh is occluded by a previously rendered object, or VIEW_CULLED if all + * triangles are entirely outside the view frustum or backface culled. + */ + virtual CullingResult TestTriangles(const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix = nullptr, BackfaceWinding bfWinding = BACKFACE_CW, ClipPlanes clipPlaneMask = CLIP_PLANE_ALL, const VertexLayout &vtxLayout = VertexLayout(16, 4, 12)) = 0; + + /*! + * \brief Perform input assembly, clipping , projection, triangle setup, and write + * triangles to the screen space bins they overlap. This function can be used to + * distribute work for threading (See the CullingThreadpool class for an example) + * + * \param inVtx Pointer to an array of input vertices, should point to the x component + * of the first vertex. The input vertices are given as (x,y,w) coordinates + * in clip space. The memory layout can be changed using vtxLayout. + * \param inTris Pointer to an array of vertex indices. Each triangle is created + * from three indices consecutively fetched from the array. + * \param nTris The number of triangles to render (inTris must contain atleast 3*nTris + * entries) + * \param triLists Pointer to an array of TriList objects with one TriList object per + * bin. If a triangle overlaps a bin, it will be written to the corresponding + * trilist. Note that this method appends the triangles to the current list, to + * start writing from the beginning of the list, set triList.mTriIdx = 0 + * \param nBinsW Number of vertical bins, the screen is divided into nBinsW x nBinsH + * rectangular bins. + * \param nBinsH Number of horizontal bins, the screen is divided into nBinsW x nBinsH + * rectangular bins. + * \param modelToClipMatrix all vertices will be transformed by this matrix before + * performing projection. If nullptr is passed the transform step will be skipped + * \param clipPlaneMask A mask indicating which clip planes should be considered by the + * triangle clipper. Can be used as an optimization if your application can + * determine (for example during culling) that a group of triangles does not + * intersect a certain frustum plane. However, setting an incorrect mask may + * cause out of bounds memory accesses. + * \param vtxLayout A struct specifying the vertex layout (see struct for detailed + * description). For best performance, it is advisable to store position data + * as compactly in memory as possible. + * \param bfWinding Sets triangle winding order to consider backfacing, must be one one + * of (BACKFACE_NONE, BACKFACE_CW and BACKFACE_CCW). Back-facing triangles are culled + * and will not be binned / rasterized. You may use BACKFACE_NONE to disable culling + * for double sided geometry + */ + virtual void BinTriangles(const float *inVtx, const unsigned int *inTris, int nTris, TriList *triLists, unsigned int nBinsW, unsigned int nBinsH, const float *modelToClipMatrix = nullptr, BackfaceWinding bfWinding = BACKFACE_CW, ClipPlanes clipPlaneMask = CLIP_PLANE_ALL, const VertexLayout &vtxLayout = VertexLayout(16, 4, 12)) = 0; + + /*! + * \brief Renders all occluder triangles in a trilist. This function can be used in + * combination with BinTriangles() to create a threded (binning) rasterizer. The + * bins can be processed independently by different threads without risking writing + * to overlapping memory regions. + * + * \param triLists A triangle list, filled using the BinTriangles() function that is to + * be rendered. + * \param scissor A scissor box limiting the rendering region to the bin. The size of each + * bin must be a multiple of 32x8 pixels due to implementation constraints. For a + * render target with (width, height) resolution and (nBinsW, nBinsH) bins, the + * size of a bin is: + * binWidth = (width / nBinsW) - (width / nBinsW) % 32; + * binHeight = (height / nBinsH) - (height / nBinsH) % 8; + * The last row and column of tiles have a different size: + * lastColBinWidth = width - (nBinsW-1)*binWidth; + * lastRowBinHeight = height - (nBinsH-1)*binHeight; + */ + virtual void RenderTrilist(const TriList &triList, const ScissorRect *scissor) = 0; + + /*! + * \brief Creates a per-pixel depth buffer from the hierarchical z buffer representation. + * Intended for visualizing the hierarchical depth buffer for debugging. The + * buffer is written in scanline order, from the top to bottom (D3D) or bottom to + * top (OGL) of the surface. See the USE_D3D define. + * + * \param depthData Pointer to memory where the per-pixel depth data is written. Must + * hold storage for atleast width*height elements as set by setResolution. + */ + virtual void ComputePixelDepthBuffer(float *depthData, bool flipY) = 0; + + /*! + * \brief Fetch occlusion culling statistics, returns zeroes if ENABLE_STATS define is + * not defined. The statistics can be used for profiling or debugging. + */ + virtual OcclusionCullingStatistics GetStatistics() = 0; + + /*! + * \brief Returns the implementation (CPU instruction set) version of this object. + */ + virtual Implementation GetImplementation() = 0; + + /*! + * \brief Utility function for transforming vertices and outputting them to an (x,y,z,w) + * format suitable for the occluder rasterization and occludee testing functions. + * + * \param mtx Pointer to matrix data. The matrix should column major for post + * multiplication (OGL) and row major for pre-multiplication (DX). This is + * consistent with OpenGL / DirectX behavior. + * \param inVtx Pointer to an array of input vertices. The input vertices are given as + * (x,y,z) coordinates. The memory layout can be changed using vtxLayout. + * \param xfVtx Pointer to an array to store transformed vertices. The transformed + * vertices are always stored as array of structs (AoS) (x,y,z,w) packed in memory. + * \param nVtx Number of vertices to transform. + * \param vtxLayout A struct specifying the vertex layout (see struct for detailed + * description). For best performance, it is advisable to store position data + * as compactly in memory as possible. Note that for this function, the + * w-component is assumed to be 1.0. + */ + static void TransformVertices(const float *mtx, const float *inVtx, float *xfVtx, unsigned int nVtx, const VertexLayout &vtxLayout = VertexLayout(12, 4, 8)); + + /*! + * \brief Get used memory alloc/free callbacks. + */ + void GetAllocFreeCallback( pfnAlignedAlloc & allocCallback, pfnAlignedFree & freeCallback ) { allocCallback = mAlignedAllocCallback, freeCallback = mAlignedFreeCallback; } + +#if MOC_RECORDER_ENABLE + /*! + * \brief Start recording subsequent rasterization and testing calls using the FrameRecorder. + * The function calls that are recorded are: + * - ClearBuffer + * - RenderTriangles + * - TestTriangles + * - TestRect + * All inputs and outputs are recorded, which can be used for correctness validation + * and performance testing. + * + * \param outputFilePath Pointer to name of the output file. + * \return 'true' if recording was started successfully, 'false' otherwise (file access error). + */ + bool RecorderStart( const char * outputFilePath ) const; + + /*! + * \brief Stop recording, flush output and release used memory. + */ + void RecorderStop( ) const; + + /*! + * \brief Manually record triangles. This is called automatically from MaskedOcclusionCulling::RenderTriangles + * if the recording is started, but not from BinTriangles/RenderTrilist (used in multithreaded codepath), in + * which case it has to be called manually. + * + * \param inVtx Pointer to an array of input vertices, should point to the x component + * of the first vertex. The input vertices are given as (x,y,w) coordinates + * in clip space. The memory layout can be changed using vtxLayout. + * \param inTris Pointer to an array of triangle indices. Each triangle is created + * from three indices consecutively fetched from the array. + * \param nTris The number of triangles to render (inTris must contain atleast 3*nTris + * entries) + * \param modelToClipMatrix all vertices will be transformed by this matrix before + * performing projection. If nullptr is passed the transform step will be skipped + * \param bfWinding Sets triangle winding order to consider backfacing, must be one one + * of (BACKFACE_NONE, BACKFACE_CW and BACKFACE_CCW). Back-facing triangles are culled + * and will not be occlusion tested. You may use BACKFACE_NONE to disable culling + * for double sided geometry + * \param clipPlaneMask A mask indicating which clip planes should be considered by the + * triangle clipper. Can be used as an optimization if your application can + * determine (for example during culling) that a group of triangles does not + * intersect a certain frustum plane. However, setting an incorrect mask may + * cause out of bounds memory accesses. + * \param vtxLayout A struct specifying the vertex layout (see struct for detailed + * description). For best performance, it is advisable to store position data + * as compactly in memory as possible. + * \param cullingResult cull result value expected to be returned by executing the + * RenderTriangles call with recorded parameters. + */ + // + // merge the binned data back into original layout; in this case, call it manually from your Threadpool implementation (already added to CullingThreadpool). + // If recording is not enabled, calling this function will do nothing. + void RecordRenderTriangles( const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix = nullptr, ClipPlanes clipPlaneMask = CLIP_PLANE_ALL, BackfaceWinding bfWinding = BACKFACE_CW, const VertexLayout &vtxLayout = VertexLayout( 16, 4, 12 ), CullingResult cullingResult = (CullingResult)-1 ); +#endif // #if MOC_RECORDER_ENABLE + +protected: + pfnAlignedAlloc mAlignedAllocCallback; + pfnAlignedFree mAlignedFreeCallback; + + mutable OcclusionCullingStatistics mStats; + +#if MOC_RECORDER_ENABLE + mutable FrameRecorder * mRecorder; + mutable std::mutex mRecorderMutex; +#endif // #if MOC_RECORDER_ENABLE + + virtual ~MaskedOcclusionCulling() {} +}; diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp new file mode 100644 index 0000000000..b129f12943 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX2.cpp @@ -0,0 +1,243 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include "MaskedOcclusionCulling.h" +#include "CompilerSpecific.inl" + +#if MOC_RECORDER_ENABLE +#include "FrameRecorder.h" +#endif + +#if defined(__MICROSOFT_COMPILER) && _MSC_VER < 1900 + // If you remove/comment this error, the code will compile & use the SSE41 version instead. + #error Older versions than visual studio 2015 not supported due to compiler bug(s) +#endif + +#if !defined(__MICROSOFT_COMPILER) || _MSC_VER >= 1900 + +// For performance reasons, the MaskedOcclusionCullingAVX2.cpp file should be compiled with VEX encoding for SSE instructions (to avoid +// AVX-SSE transition penalties, see https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties). However, the SSE +// version in MaskedOcclusionCulling.cpp _must_ be compiled without VEX encoding to allow backwards compatibility. Best practice is to +// use lowest supported target platform (e.g. /arch:SSE2) as project default, and elevate only the MaskedOcclusionCullingAVX2/512.cpp files. +#ifndef __AVX2__ + #error For best performance, MaskedOcclusionCullingAVX2.cpp should be compiled with /arch:AVX2 +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AVX specific defines and constants +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SIMD_LANES 8 +#define TILE_HEIGHT_SHIFT 3 + +#define SIMD_LANE_IDX _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7) + +#define SIMD_SUB_TILE_COL_OFFSET _mm256_setr_epi32(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET _mm256_setr_epi32(0, 0, 0, 0, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT) +#define SIMD_SUB_TILE_COL_OFFSET_F _mm256_setr_ps(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET_F _mm256_setr_ps(0, 0, 0, 0, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT) + +#define SIMD_SHUFFLE_SCANLINE_TO_SUBTILES _mm256_setr_epi8(0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF, 0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF) + +#define SIMD_LANE_YCOORD_I _mm256_setr_epi32(128, 384, 640, 896, 1152, 1408, 1664, 1920) +#define SIMD_LANE_YCOORD_F _mm256_setr_ps(128.0f, 384.0f, 640.0f, 896.0f, 1152.0f, 1408.0f, 1664.0f, 1920.0f) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AVX specific typedefs and functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef __m256 __mw; +typedef __m256i __mwi; + +#define _mmw_set1_ps _mm256_set1_ps +#define _mmw_setzero_ps _mm256_setzero_ps +#define _mmw_and_ps _mm256_and_ps +#define _mmw_or_ps _mm256_or_ps +#define _mmw_xor_ps _mm256_xor_ps +#define _mmw_not_ps(a) _mm256_xor_ps((a), _mm256_castsi256_ps(_mm256_set1_epi32(~0))) +#define _mmw_andnot_ps _mm256_andnot_ps +#define _mmw_neg_ps(a) _mm256_xor_ps((a), _mm256_set1_ps(-0.0f)) +#define _mmw_abs_ps(a) _mm256_and_ps((a), _mm256_castsi256_ps(_mm256_set1_epi32(0x7FFFFFFF))) +#define _mmw_add_ps _mm256_add_ps +#define _mmw_sub_ps _mm256_sub_ps +#define _mmw_mul_ps _mm256_mul_ps +#define _mmw_div_ps _mm256_div_ps +#define _mmw_min_ps _mm256_min_ps +#define _mmw_max_ps _mm256_max_ps +#define _mmw_fmadd_ps _mm256_fmadd_ps +#define _mmw_fmsub_ps _mm256_fmsub_ps +#define _mmw_movemask_ps _mm256_movemask_ps +#define _mmw_blendv_ps _mm256_blendv_ps +#define _mmw_cmpge_ps(a,b) _mm256_cmp_ps(a, b, _CMP_GE_OQ) +#define _mmw_cmpgt_ps(a,b) _mm256_cmp_ps(a, b, _CMP_GT_OQ) +#define _mmw_cmpeq_ps(a,b) _mm256_cmp_ps(a, b, _CMP_EQ_OQ) +#define _mmw_floor_ps(x) _mm256_round_ps(x, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC) +#define _mmw_ceil_ps(x) _mm256_round_ps(x, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC) +#define _mmw_shuffle_ps _mm256_shuffle_ps +#define _mmw_insertf32x4_ps _mm256_insertf128_ps +#define _mmw_cvtepi32_ps _mm256_cvtepi32_ps +#define _mmw_blendv_epi32(a,b,c) simd_cast<__mwi>(_mmw_blendv_ps(simd_cast<__mw>(a), simd_cast<__mw>(b), simd_cast<__mw>(c))) + +#define _mmw_set1_epi32 _mm256_set1_epi32 +#define _mmw_setzero_epi32 _mm256_setzero_si256 +#define _mmw_and_epi32 _mm256_and_si256 +#define _mmw_or_epi32 _mm256_or_si256 +#define _mmw_xor_epi32 _mm256_xor_si256 +#define _mmw_not_epi32(a) _mm256_xor_si256((a), _mm256_set1_epi32(~0)) +#define _mmw_andnot_epi32 _mm256_andnot_si256 +#define _mmw_neg_epi32(a) _mm256_sub_epi32(_mm256_set1_epi32(0), (a)) +#define _mmw_add_epi32 _mm256_add_epi32 +#define _mmw_sub_epi32 _mm256_sub_epi32 +#define _mmw_min_epi32 _mm256_min_epi32 +#define _mmw_max_epi32 _mm256_max_epi32 +#define _mmw_subs_epu16 _mm256_subs_epu16 +#define _mmw_mullo_epi32 _mm256_mullo_epi32 +#define _mmw_cmpeq_epi32 _mm256_cmpeq_epi32 +#define _mmw_testz_epi32 _mm256_testz_si256 +#define _mmw_cmpgt_epi32 _mm256_cmpgt_epi32 +#define _mmw_srai_epi32 _mm256_srai_epi32 +#define _mmw_srli_epi32 _mm256_srli_epi32 +#define _mmw_slli_epi32 _mm256_slli_epi32 +#define _mmw_sllv_ones(x) _mm256_sllv_epi32(SIMD_BITS_ONE, x) +#define _mmw_transpose_epi8(x) _mm256_shuffle_epi8(x, SIMD_SHUFFLE_SCANLINE_TO_SUBTILES) +#define _mmw_abs_epi32 _mm256_abs_epi32 +#define _mmw_cvtps_epi32 _mm256_cvtps_epi32 +#define _mmw_cvttps_epi32 _mm256_cvttps_epi32 + +#define _mmx_dp4_ps(a, b) _mm_dp_ps(a, b, 0xFF) +#define _mmx_fmadd_ps _mm_fmadd_ps +#define _mmx_max_epi32 _mm_max_epi32 +#define _mmx_min_epi32 _mm_min_epi32 + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SIMD casting functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template FORCE_INLINE T simd_cast(Y A); +template<> FORCE_INLINE __m128 simd_cast<__m128>(float A) { return _mm_set1_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128i A) { return _mm_castsi128_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128 A) { return A; } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(int A) { return _mm_set1_epi32(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128 A) { return _mm_castps_si128(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128i A) { return A; } +template<> FORCE_INLINE __m256 simd_cast<__m256>(float A) { return _mm256_set1_ps(A); } +template<> FORCE_INLINE __m256 simd_cast<__m256>(__m256i A) { return _mm256_castsi256_ps(A); } +template<> FORCE_INLINE __m256 simd_cast<__m256>(__m256 A) { return A; } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(int A) { return _mm256_set1_epi32(A); } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(__m256 A) { return _mm256_castps_si256(A); } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(__m256i A) { return A; } + +#define MAKE_ACCESSOR(name, simd_type, base_type, is_const, elements) \ + FORCE_INLINE is_const base_type * name(is_const simd_type &a) { \ + union accessor { simd_type m_native; base_type m_array[elements]; }; \ + is_const accessor *acs = reinterpret_cast(&a); \ + return acs->m_array; \ + } + +MAKE_ACCESSOR(simd_f32, __m128, float, , 4) +MAKE_ACCESSOR(simd_f32, __m128, float, const, 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, , 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, const, 4) + +MAKE_ACCESSOR(simd_f32, __m256, float, , 8) +MAKE_ACCESSOR(simd_f32, __m256, float, const, 8) +MAKE_ACCESSOR(simd_i32, __m256i, int, , 8) +MAKE_ACCESSOR(simd_i32, __m256i, int, const, 8) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Specialized AVX input assembly function for general vertex gather +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef MaskedOcclusionCulling::VertexLayout VertexLayout; + +FORCE_INLINE void GatherVertices(__m256 *vtxX, __m256 *vtxY, __m256 *vtxW, const float *inVtx, const unsigned int *inTrisPtr, int numLanes, const VertexLayout &vtxLayout) +{ + assert(numLanes >= 1); + + const __m256i SIMD_TRI_IDX_OFFSET = _mm256_setr_epi32(0, 3, 6, 9, 12, 15, 18, 21); + static const __m256i SIMD_LANE_MASK[9] = { + _mm256_setr_epi32( 0, 0, 0, 0, 0, 0, 0, 0), + _mm256_setr_epi32(~0, 0, 0, 0, 0, 0, 0, 0), + _mm256_setr_epi32(~0, ~0, 0, 0, 0, 0, 0, 0), + _mm256_setr_epi32(~0, ~0, ~0, 0, 0, 0, 0, 0), + _mm256_setr_epi32(~0, ~0, ~0, ~0, 0, 0, 0, 0), + _mm256_setr_epi32(~0, ~0, ~0, ~0, ~0, 0, 0, 0), + _mm256_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, 0, 0), + _mm256_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, 0), + _mm256_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0) + }; + + // Compute per-lane index list offset that guards against out of bounds memory accesses + __m256i safeTriIdxOffset = _mm256_and_si256(SIMD_TRI_IDX_OFFSET, SIMD_LANE_MASK[numLanes]); + + // Fetch triangle indices. + __m256i vtxIdx[3]; + vtxIdx[0] = _mmw_mullo_epi32(_mm256_i32gather_epi32((const int*)inTrisPtr + 0, safeTriIdxOffset, 4), _mmw_set1_epi32(vtxLayout.mStride)); + vtxIdx[1] = _mmw_mullo_epi32(_mm256_i32gather_epi32((const int*)inTrisPtr + 1, safeTriIdxOffset, 4), _mmw_set1_epi32(vtxLayout.mStride)); + vtxIdx[2] = _mmw_mullo_epi32(_mm256_i32gather_epi32((const int*)inTrisPtr + 2, safeTriIdxOffset, 4), _mmw_set1_epi32(vtxLayout.mStride)); + + char *vPtr = (char *)inVtx; + + // Fetch triangle vertices + for (int i = 0; i < 3; i++) + { + vtxX[i] = _mm256_i32gather_ps((float *)vPtr, vtxIdx[i], 1); + vtxY[i] = _mm256_i32gather_ps((float *)(vPtr + vtxLayout.mOffsetY), vtxIdx[i], 1); + vtxW[i] = _mm256_i32gather_ps((float *)(vPtr + vtxLayout.mOffsetW), vtxIdx[i], 1); + } +} + +namespace MaskedOcclusionCullingAVX2 +{ + static MaskedOcclusionCulling::Implementation gInstructionSet = MaskedOcclusionCulling::AVX2; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Include common algorithm implementation (general, SIMD independent code) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #include "MaskedOcclusionCullingCommon.inl" + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Utility function to create a new object using the allocator callbacks + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + typedef MaskedOcclusionCulling::pfnAlignedAlloc pfnAlignedAlloc; + typedef MaskedOcclusionCulling::pfnAlignedFree pfnAlignedFree; + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + MaskedOcclusionCullingPrivate *object = (MaskedOcclusionCullingPrivate *)alignedAlloc(64, sizeof(MaskedOcclusionCullingPrivate)); + new (object) MaskedOcclusionCullingPrivate(alignedAlloc, alignedFree); + return object; + } +}; + +#else + +namespace MaskedOcclusionCullingAVX2 +{ + typedef MaskedOcclusionCulling::pfnAlignedAlloc pfnAlignedAlloc; + typedef MaskedOcclusionCulling::pfnAlignedFree pfnAlignedFree; + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + return nullptr; + } +}; + +#endif diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp new file mode 100644 index 0000000000..1dccccd83e --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingAVX512.cpp @@ -0,0 +1,309 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include "MaskedOcclusionCulling.h" +#include "CompilerSpecific.inl" + +#if MOC_RECORDER_ENABLE +#include "FrameRecorder.h" +#endif + +// Make sure compiler supports AVX-512 intrinsics: Visual Studio 2017 (Update 3) || Intel C++ Compiler 16.0 || Clang 4.0 || GCC 5.0 +#if USE_AVX512 != 0 && ((defined(_MSC_VER) && _MSC_VER >= 1911) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1600) || (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && __GNUC__ >= 5)) + +// The MaskedOcclusionCullingAVX512.cpp file should be compiled avx2/avx512 architecture options turned on in the compiler. However, the SSE +// version in MaskedOcclusionCulling.cpp _must_ be compiled with SSE2 architecture allow backwards compatibility. Best practice is to +// use lowest supported target platform (e.g. /arch:SSE2) as project default, and elevate only the MaskedOcclusionCullingAVX2/512.cpp files. +#ifndef __AVX2__ + #error For best performance, MaskedOcclusionCullingAVX512.cpp should be compiled with /arch:AVX2 +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AVX specific defines and constants +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SIMD_LANES 16 +#define TILE_HEIGHT_SHIFT 4 + +#define SIMD_LANE_IDX _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) + +#define SIMD_SUB_TILE_COL_OFFSET _mm512_setr_epi32(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET _mm512_setr_epi32(0, 0, 0, 0, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3) +#define SIMD_SUB_TILE_COL_OFFSET_F _mm512_setr_ps(0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3, 0, SUB_TILE_WIDTH, SUB_TILE_WIDTH * 2, SUB_TILE_WIDTH * 3) +#define SIMD_SUB_TILE_ROW_OFFSET_F _mm512_setr_ps(0, 0, 0, 0, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 2, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3, SUB_TILE_HEIGHT * 3) + +#define SIMD_SHUFFLE_SCANLINE_TO_SUBTILES _mm512_set_epi32(0x0F0B0703, 0x0E0A0602, 0x0D090501, 0x0C080400, 0x0F0B0703, 0x0E0A0602, 0x0D090501, 0x0C080400, 0x0F0B0703, 0x0E0A0602, 0x0D090501, 0x0C080400, 0x0F0B0703, 0x0E0A0602, 0x0D090501, 0x0C080400) + +#define SIMD_LANE_YCOORD_I _mm512_setr_epi32(128, 384, 640, 896, 1152, 1408, 1664, 1920, 2176, 2432, 2688, 2944, 3200, 3456, 3712, 3968) +#define SIMD_LANE_YCOORD_F _mm512_setr_ps(128.0f, 384.0f, 640.0f, 896.0f, 1152.0f, 1408.0f, 1664.0f, 1920.0f, 2176.0f, 2432.0f, 2688.0f, 2944.0f, 3200.0f, 3456.0f, 3712.0f, 3968.0f) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AVX specific typedefs and functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef __m512 __mw; +typedef __m512i __mwi; + +#define _mmw_set1_ps _mm512_set1_ps +#define _mmw_setzero_ps _mm512_setzero_ps +#define _mmw_and_ps _mm512_and_ps +#define _mmw_or_ps _mm512_or_ps +#define _mmw_xor_ps _mm512_xor_ps +#define _mmw_not_ps(a) _mm512_xor_ps((a), _mm512_castsi512_ps(_mm512_set1_epi32(~0))) +#define _mmw_andnot_ps _mm512_andnot_ps +#define _mmw_neg_ps(a) _mm512_xor_ps((a), _mm512_set1_ps(-0.0f)) +#define _mmw_abs_ps(a) _mm512_and_ps((a), _mm512_castsi512_ps(_mm512_set1_epi32(0x7FFFFFFF))) +#define _mmw_add_ps _mm512_add_ps +#define _mmw_sub_ps _mm512_sub_ps +#define _mmw_mul_ps _mm512_mul_ps +#define _mmw_div_ps _mm512_div_ps +#define _mmw_min_ps _mm512_min_ps +#define _mmw_max_ps _mm512_max_ps +#define _mmw_fmadd_ps _mm512_fmadd_ps +#define _mmw_fmsub_ps _mm512_fmsub_ps +#define _mmw_shuffle_ps _mm512_shuffle_ps +#define _mmw_insertf32x4_ps _mm512_insertf32x4 +#define _mmw_cvtepi32_ps _mm512_cvtepi32_ps +#define _mmw_blendv_epi32(a,b,c) simd_cast<__mwi>(_mmw_blendv_ps(simd_cast<__mw>(a), simd_cast<__mw>(b), simd_cast<__mw>(c))) + +#define _mmw_set1_epi32 _mm512_set1_epi32 +#define _mmw_setzero_epi32 _mm512_setzero_si512 +#define _mmw_and_epi32 _mm512_and_si512 +#define _mmw_or_epi32 _mm512_or_si512 +#define _mmw_xor_epi32 _mm512_xor_si512 +#define _mmw_not_epi32(a) _mm512_xor_si512((a), _mm512_set1_epi32(~0)) +#define _mmw_andnot_epi32 _mm512_andnot_si512 +#define _mmw_neg_epi32(a) _mm512_sub_epi32(_mm512_set1_epi32(0), (a)) +#define _mmw_add_epi32 _mm512_add_epi32 +#define _mmw_sub_epi32 _mm512_sub_epi32 +#define _mmw_min_epi32 _mm512_min_epi32 +#define _mmw_max_epi32 _mm512_max_epi32 +#define _mmw_subs_epu16 _mm512_subs_epu16 +#define _mmw_mullo_epi32 _mm512_mullo_epi32 +#define _mmw_srai_epi32 _mm512_srai_epi32 +#define _mmw_srli_epi32 _mm512_srli_epi32 +#define _mmw_slli_epi32 _mm512_slli_epi32 +#define _mmw_sllv_ones(x) _mm512_sllv_epi32(SIMD_BITS_ONE, x) +#define _mmw_transpose_epi8(x) _mm512_shuffle_epi8(x, SIMD_SHUFFLE_SCANLINE_TO_SUBTILES) +#define _mmw_abs_epi32 _mm512_abs_epi32 +#define _mmw_cvtps_epi32 _mm512_cvtps_epi32 +#define _mmw_cvttps_epi32 _mm512_cvttps_epi32 + +#define _mmx_dp4_ps(a, b) _mm_dp_ps(a, b, 0xFF) +#define _mmx_fmadd_ps _mm_fmadd_ps +#define _mmx_max_epi32 _mm_max_epi32 +#define _mmx_min_epi32 _mm_min_epi32 + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SIMD casting functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template FORCE_INLINE T simd_cast(Y A); +template<> FORCE_INLINE __m128 simd_cast<__m128>(float A) { return _mm_set1_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128i A) { return _mm_castsi128_ps(A); } +template<> FORCE_INLINE __m128 simd_cast<__m128>(__m128 A) { return A; } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(int A) { return _mm_set1_epi32(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128 A) { return _mm_castps_si128(A); } +template<> FORCE_INLINE __m128i simd_cast<__m128i>(__m128i A) { return A; } +template<> FORCE_INLINE __m256 simd_cast<__m256>(float A) { return _mm256_set1_ps(A); } +template<> FORCE_INLINE __m256 simd_cast<__m256>(__m256i A) { return _mm256_castsi256_ps(A); } +template<> FORCE_INLINE __m256 simd_cast<__m256>(__m256 A) { return A; } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(int A) { return _mm256_set1_epi32(A); } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(__m256 A) { return _mm256_castps_si256(A); } +template<> FORCE_INLINE __m256i simd_cast<__m256i>(__m256i A) { return A; } +template<> FORCE_INLINE __m512 simd_cast<__m512>(float A) { return _mm512_set1_ps(A); } +template<> FORCE_INLINE __m512 simd_cast<__m512>(__m512i A) { return _mm512_castsi512_ps(A); } +template<> FORCE_INLINE __m512 simd_cast<__m512>(__m512 A) { return A; } +template<> FORCE_INLINE __m512i simd_cast<__m512i>(int A) { return _mm512_set1_epi32(A); } +template<> FORCE_INLINE __m512i simd_cast<__m512i>(__m512 A) { return _mm512_castps_si512(A); } +template<> FORCE_INLINE __m512i simd_cast<__m512i>(__m512i A) { return A; } + +#define MAKE_ACCESSOR(name, simd_type, base_type, is_const, elements) \ + FORCE_INLINE is_const base_type * name(is_const simd_type &a) { \ + union accessor { simd_type m_native; base_type m_array[elements]; }; \ + is_const accessor *acs = reinterpret_cast(&a); \ + return acs->m_array; \ + } + +MAKE_ACCESSOR(simd_f32, __m128, float, , 4) +MAKE_ACCESSOR(simd_f32, __m128, float, const, 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, , 4) +MAKE_ACCESSOR(simd_i32, __m128i, int, const, 4) + +MAKE_ACCESSOR(simd_f32, __m256, float, , 8) +MAKE_ACCESSOR(simd_f32, __m256, float, const, 8) +MAKE_ACCESSOR(simd_i32, __m256i, int, , 8) +MAKE_ACCESSOR(simd_i32, __m256i, int, const, 8) + +MAKE_ACCESSOR(simd_f32, __m512, float, , 16) +MAKE_ACCESSOR(simd_f32, __m512, float, const, 16) +MAKE_ACCESSOR(simd_i32, __m512i, int, , 16) +MAKE_ACCESSOR(simd_i32, __m512i, int, const, 16) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Specialized AVX input assembly function for general vertex gather +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef MaskedOcclusionCulling::VertexLayout VertexLayout; + +FORCE_INLINE void GatherVertices(__m512 *vtxX, __m512 *vtxY, __m512 *vtxW, const float *inVtx, const unsigned int *inTrisPtr, int numLanes, const VertexLayout &vtxLayout) +{ + assert(numLanes >= 1); + + const __m512i SIMD_TRI_IDX_OFFSET = _mm512_setr_epi32(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45); + static const __m512i SIMD_LANE_MASK[17] = { + _mm512_setr_epi32( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0), + _mm512_setr_epi32(~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0) + }; + + // Compute per-lane index list offset that guards against out of bounds memory accesses + __m512i safeTriIdxOffset = _mm512_and_si512(SIMD_TRI_IDX_OFFSET, SIMD_LANE_MASK[numLanes]); + + // Fetch triangle indices. + __m512i vtxIdx[3]; + vtxIdx[0] = _mmw_mullo_epi32(_mm512_i32gather_epi32(safeTriIdxOffset, (const int*)inTrisPtr + 0, 4), _mmw_set1_epi32(vtxLayout.mStride)); + vtxIdx[1] = _mmw_mullo_epi32(_mm512_i32gather_epi32(safeTriIdxOffset, (const int*)inTrisPtr + 1, 4), _mmw_set1_epi32(vtxLayout.mStride)); + vtxIdx[2] = _mmw_mullo_epi32(_mm512_i32gather_epi32(safeTriIdxOffset, (const int*)inTrisPtr + 2, 4), _mmw_set1_epi32(vtxLayout.mStride)); + + char *vPtr = (char *)inVtx; + + // Fetch triangle vertices + for (int i = 0; i < 3; i++) + { + vtxX[i] = _mm512_i32gather_ps(vtxIdx[i], (float *)vPtr, 1); + vtxY[i] = _mm512_i32gather_ps(vtxIdx[i], (float *)(vPtr + vtxLayout.mOffsetY), 1); + vtxW[i] = _mm512_i32gather_ps(vtxIdx[i], (float *)(vPtr + vtxLayout.mOffsetW), 1); + } +} + +namespace MaskedOcclusionCullingAVX512 +{ + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Poorly implemented functions. TODO: fix common (maskedOcclusionCullingCommon.inl) code to improve perf + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FORCE_INLINE __m512 _mmw_floor_ps(__m512 x) + { + return _mm512_roundscale_ps(x, 1); // 1 = floor + } + + FORCE_INLINE __m512 _mmw_ceil_ps(__m512 x) + { + return _mm512_roundscale_ps(x, 2); // 2 = ceil + } + + FORCE_INLINE __m512i _mmw_cmpeq_epi32(__m512i a, __m512i b) + { + __mmask16 mask = _mm512_cmpeq_epi32_mask(a, b); + return _mm512_mask_mov_epi32(_mm512_set1_epi32(0), mask, _mm512_set1_epi32(~0)); + } + + FORCE_INLINE __m512i _mmw_cmpgt_epi32(__m512i a, __m512i b) + { + __mmask16 mask = _mm512_cmpgt_epi32_mask(a, b); + return _mm512_mask_mov_epi32(_mm512_set1_epi32(0), mask, _mm512_set1_epi32(~0)); + } + + FORCE_INLINE bool _mmw_testz_epi32(__m512i a, __m512i b) + { + __mmask16 mask = _mm512_cmpeq_epi32_mask(_mm512_and_si512(a, b), _mm512_set1_epi32(0)); + return mask == 0xFFFF; + } + + FORCE_INLINE __m512 _mmw_cmpge_ps(__m512 a, __m512 b) + { + __mmask16 mask = _mm512_cmp_ps_mask(a, b, _CMP_GE_OQ); + return _mm512_castsi512_ps(_mm512_mask_mov_epi32(_mm512_set1_epi32(0), mask, _mm512_set1_epi32(~0))); + } + + FORCE_INLINE __m512 _mmw_cmpgt_ps(__m512 a, __m512 b) + { + __mmask16 mask = _mm512_cmp_ps_mask(a, b, _CMP_GT_OQ); + return _mm512_castsi512_ps(_mm512_mask_mov_epi32(_mm512_set1_epi32(0), mask, _mm512_set1_epi32(~0))); + } + + FORCE_INLINE __m512 _mmw_cmpeq_ps(__m512 a, __m512 b) + { + __mmask16 mask = _mm512_cmp_ps_mask(a, b, _CMP_EQ_OQ); + return _mm512_castsi512_ps(_mm512_mask_mov_epi32(_mm512_set1_epi32(0), mask, _mm512_set1_epi32(~0))); + } + + FORCE_INLINE __mmask16 _mmw_movemask_ps(const __m512 &a) + { + __mmask16 mask = _mm512_cmp_epi32_mask(_mm512_and_si512(_mm512_castps_si512(a), _mm512_set1_epi32(0x80000000)), _mm512_set1_epi32(0), 4); // a & 0x8000000 != 0 + return mask; + } + + FORCE_INLINE __m512 _mmw_blendv_ps(const __m512 &a, const __m512 &b, const __m512 &c) + { + __mmask16 mask = _mmw_movemask_ps(c); + return _mm512_mask_mov_ps(a, mask, b); + } + + static MaskedOcclusionCulling::Implementation gInstructionSet = MaskedOcclusionCulling::AVX512; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Include common algorithm implementation (general, SIMD independent code) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #include "MaskedOcclusionCullingCommon.inl" + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Utility function to create a new object using the allocator callbacks + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + typedef MaskedOcclusionCulling::pfnAlignedAlloc pfnAlignedAlloc; + typedef MaskedOcclusionCulling::pfnAlignedFree pfnAlignedFree; + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + MaskedOcclusionCullingPrivate *object = (MaskedOcclusionCullingPrivate *)alignedAlloc(64, sizeof(MaskedOcclusionCullingPrivate)); + new (object) MaskedOcclusionCullingPrivate(alignedAlloc, alignedFree); + return object; + } +}; + +#else + +namespace MaskedOcclusionCullingAVX512 +{ + typedef MaskedOcclusionCulling::pfnAlignedAlloc pfnAlignedAlloc; + typedef MaskedOcclusionCulling::pfnAlignedFree pfnAlignedFree; + + MaskedOcclusionCulling *CreateMaskedOcclusionCulling(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) + { + return nullptr; + } +}; + +#endif diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingCommon.inl b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingCommon.inl new file mode 100644 index 0000000000..331ca69964 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/MaskedOcclusionCullingCommon.inl @@ -0,0 +1,2053 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +//////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common SIMD math utility functions +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template FORCE_INLINE T max(const T &a, const T &b) { return a > b ? a : b; } +template FORCE_INLINE T min(const T &a, const T &b) { return a < b ? a : b; } + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Common defines and constants +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SIMD_ALL_LANES_MASK ((1 << SIMD_LANES) - 1) + +// Tile dimensions are 32xN pixels. These values are not tweakable and the code must also be modified +// to support different tile sizes as it is tightly coupled with the SSE/AVX register size +#define TILE_WIDTH_SHIFT 5 +#define TILE_WIDTH (1 << TILE_WIDTH_SHIFT) +#define TILE_HEIGHT (1 << TILE_HEIGHT_SHIFT) + +// Sub-tiles (used for updating the masked HiZ buffer) are 8x4 tiles, so there are 4x2 sub-tiles in a tile +#define SUB_TILE_WIDTH 8 +#define SUB_TILE_HEIGHT 4 + +// The number of fixed point bits used to represent vertex coordinates / edge slopes. +#if PRECISE_COVERAGE != 0 + #define FP_BITS 8 + #define FP_HALF_PIXEL (1 << (FP_BITS - 1)) + #define FP_INV (1.0f / (float)(1 << FP_BITS)) +#else + // Note that too low precision, without precise coverage, may cause overshoots / false coverage during rasterization. + // This is configured for 14 bits for AVX512 and 16 bits for SSE. Max tile slope delta is roughly + // (screenWidth + 2*(GUARD_BAND_PIXEL_SIZE + 1)) * (2^FP_BITS * (TILE_HEIGHT + GUARD_BAND_PIXEL_SIZE + 1)) + // and must fit in 31 bits. With this config, max image resolution (width) is ~3272, so stay well clear of this limit. + #define FP_BITS (19 - TILE_HEIGHT_SHIFT) +#endif + +// Tile dimensions in fixed point coordinates +#define FP_TILE_HEIGHT_SHIFT (FP_BITS + TILE_HEIGHT_SHIFT) +#define FP_TILE_HEIGHT (1 << FP_TILE_HEIGHT_SHIFT) + +// Maximum number of triangles that may be generated during clipping. We process SIMD_LANES triangles at a time and +// clip against 5 planes, so the max should be 5*8 = 40 (we immediately draw the first clipped triangle). +// This number must be a power of two. +#define MAX_CLIPPED (8*SIMD_LANES) +#define MAX_CLIPPED_WRAP (MAX_CLIPPED - 1) + +// Size of guard band in pixels. Clipping doesn't seem to be very expensive so we use a small guard band +// to improve rasterization performance. It's not recommended to set the guard band to zero, as this may +// cause leakage along the screen border due to precision/rounding. +#define GUARD_BAND_PIXEL_SIZE 1.0f + +// We classify triangles as big if the bounding box is wider than this given threshold and use a tighter +// but slightly more expensive traversal algorithm. This improves performance greatly for sliver triangles +#define BIG_TRIANGLE 3 + +// Only gather statistics if enabled. +#if ENABLE_STATS != 0 + #define STATS_ADD(var, val) _InterlockedExchangeAdd64( &var, val ) +#else + #define STATS_ADD(var, val) +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SIMD common defines (constant values) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SIMD_BITS_ONE _mmw_set1_epi32(~0) +#define SIMD_BITS_ZERO _mmw_setzero_epi32() +#define SIMD_TILE_WIDTH _mmw_set1_epi32(TILE_WIDTH) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Vertex fetch utility function, need to be in global namespace due to template specialization +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template FORCE_INLINE void VtxFetch4(__mw *v, const unsigned int *inTrisPtr, int triVtx, const float *inVtx, int numLanes) +{ + // Fetch 4 vectors (matching 1 sse part of the SIMD register), and continue to the next + const int ssePart = (SIMD_LANES / 4) - N; + for (int k = 0; k < 4; k++) + { + int lane = 4 * ssePart + k; + if (numLanes > lane) + v[k] = _mmw_insertf32x4_ps(v[k], _mm_loadu_ps(&inVtx[inTrisPtr[lane * 3 + triVtx] << 2]), ssePart); + } + VtxFetch4(v, inTrisPtr, triVtx, inVtx, numLanes); +} + +template<> FORCE_INLINE void VtxFetch4<0>(__mw *v, const unsigned int *inTrisPtr, int triVtx, const float *inVtx, int numLanes) +{ + // Workaround for unused parameter warning + (void)v; (void)inTrisPtr; (void)triVtx; (void)inVtx; (void)numLanes; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Private class containing the implementation +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class MaskedOcclusionCullingPrivate : public MaskedOcclusionCulling +{ +public: + struct ZTile + { + __mw mZMin[2]; + __mwi mMask; + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Member variables + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + __mw mHalfWidth; + __mw mHalfHeight; + __mw mCenterX; + __mw mCenterY; + __m128 mCSFrustumPlanes[5]; + __m128 mIHalfSize; + __m128 mICenter; + __m128i mIScreenSize; + + float mNearDist; + int mWidth; + int mHeight; + int mTilesWidth; + int mTilesHeight; + + ZTile *mMaskedHiZBuffer; + ScissorRect mFullscreenScissor; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Constructors and state handling + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MaskedOcclusionCullingPrivate(pfnAlignedAlloc alignedAlloc, pfnAlignedFree alignedFree) : mFullscreenScissor(0, 0, 0, 0) + { + mMaskedHiZBuffer = nullptr; + mAlignedAllocCallback = alignedAlloc; + mAlignedFreeCallback = alignedFree; +#if MOC_RECORDER_ENABLE + mRecorder = nullptr; +#endif + + SetNearClipPlane(0.0f); + mCSFrustumPlanes[0] = _mm_setr_ps(0.0f, 0.0f, 1.0f, 0.0f); + mCSFrustumPlanes[1] = _mm_setr_ps(1.0f, 0.0f, 1.0f, 0.0f); + mCSFrustumPlanes[2] = _mm_setr_ps(-1.0f, 0.0f, 1.0f, 0.0f); + mCSFrustumPlanes[3] = _mm_setr_ps(0.0f, 1.0f, 1.0f, 0.0f); + mCSFrustumPlanes[4] = _mm_setr_ps(0.0f, -1.0f, 1.0f, 0.0f); + + memset(&mStats, 0, sizeof(OcclusionCullingStatistics)); + + SetResolution(0, 0); + } + + ~MaskedOcclusionCullingPrivate() override + { + if (mMaskedHiZBuffer != nullptr) + mAlignedFreeCallback(mMaskedHiZBuffer); + mMaskedHiZBuffer = nullptr; + +#if MOC_RECORDER_ENABLE + assert( mRecorder == nullptr ); // forgot to call StopRecording()? +#endif + } + + void SetResolution(unsigned int width, unsigned int height) override + { + // Resolution must be a multiple of the subtile size + assert(width % SUB_TILE_WIDTH == 0 && height % SUB_TILE_HEIGHT == 0); +#if PRECISE_COVERAGE == 0 + // Test if combination of resolution & SLOPE_FP_BITS bits may cause 32-bit overflow. Note that the maximum resolution estimate + // is only an estimate (not conservative). It's advicable to stay well below the limit. + assert(width < ((1U << 31) - 1U) / ((1U << FP_BITS) * (TILE_HEIGHT + (unsigned int)(GUARD_BAND_PIXEL_SIZE + 1.0f))) - (2U * (unsigned int)(GUARD_BAND_PIXEL_SIZE + 1.0f))); +#endif + + // Delete current masked hierarchical Z buffer + if (mMaskedHiZBuffer != nullptr) + mAlignedFreeCallback(mMaskedHiZBuffer); + mMaskedHiZBuffer = nullptr; + + // Setup various resolution dependent constant values + mWidth = (int)width; + mHeight = (int)height; + mTilesWidth = (int)(width + TILE_WIDTH - 1) >> TILE_WIDTH_SHIFT; + mTilesHeight = (int)(height + TILE_HEIGHT - 1) >> TILE_HEIGHT_SHIFT; + mCenterX = _mmw_set1_ps((float)mWidth * 0.5f); + mCenterY = _mmw_set1_ps((float)mHeight * 0.5f); + mICenter = _mm_setr_ps((float)mWidth * 0.5f, (float)mWidth * 0.5f, (float)mHeight * 0.5f, (float)mHeight * 0.5f); + mHalfWidth = _mmw_set1_ps((float)mWidth * 0.5f); +#if USE_D3D != 0 + mHalfHeight = _mmw_set1_ps((float)-mHeight * 0.5f); + mIHalfSize = _mm_setr_ps((float)mWidth * 0.5f, (float)mWidth * 0.5f, (float)-mHeight * 0.5f, (float)-mHeight * 0.5f); +#else + mHalfHeight = _mmw_set1_ps((float)mHeight * 0.5f); + mIHalfSize = _mm_setr_ps((float)mWidth * 0.5f, (float)mWidth * 0.5f, (float)mHeight * 0.5f, (float)mHeight * 0.5f); +#endif + mIScreenSize = _mm_setr_epi32(mWidth - 1, mWidth - 1, mHeight - 1, mHeight - 1); + + // Setup a full screen scissor rectangle + mFullscreenScissor.mMinX = 0; + mFullscreenScissor.mMinY = 0; + mFullscreenScissor.mMaxX = mTilesWidth << TILE_WIDTH_SHIFT; + mFullscreenScissor.mMaxY = mTilesHeight << TILE_HEIGHT_SHIFT; + + // Adjust clip planes to include a small guard band to avoid clipping leaks + if (mWidth > 0.0f && mHeight > 0.0f) + { + float guardBandWidth = (2.0f / (float)mWidth) * GUARD_BAND_PIXEL_SIZE; + float guardBandHeight = (2.0f / (float)mHeight) * GUARD_BAND_PIXEL_SIZE; + mCSFrustumPlanes[1] = _mm_setr_ps(1.0f - guardBandWidth, 0.0f, 1.0f, 0.0f); + mCSFrustumPlanes[2] = _mm_setr_ps(-1.0f + guardBandWidth, 0.0f, 1.0f, 0.0f); + mCSFrustumPlanes[3] = _mm_setr_ps(0.0f, 1.0f - guardBandHeight, 1.0f, 0.0f); + mCSFrustumPlanes[4] = _mm_setr_ps(0.0f, -1.0f + guardBandHeight, 1.0f, 0.0f); + } + + // Allocate masked hierarchical Z buffer (if zero size leave at nullptr) + if(mTilesWidth * mTilesHeight > 0) + mMaskedHiZBuffer = (ZTile *)mAlignedAllocCallback(64, sizeof(ZTile) * mTilesWidth * mTilesHeight); + } + + void GetResolution(unsigned int &width, unsigned int &height) const override + { + width = mWidth; + height = mHeight; + } + + void ComputeBinWidthHeight(unsigned int nBinsW, unsigned int nBinsH, unsigned int & outBinWidth, unsigned int & outBinHeight) override + { + outBinWidth = (mWidth / nBinsW) - ((mWidth / nBinsW) % TILE_WIDTH); + outBinHeight = (mHeight / nBinsH) - ((mHeight / nBinsH) % TILE_HEIGHT); + } + + void SetNearClipPlane(float nearDist) override + { + // Setup the near frustum plane + mNearDist = nearDist; + mCSFrustumPlanes[0] = _mm_setr_ps(0.0f, 0.0f, 1.0f, -nearDist); + } + + float GetNearClipPlane() const override + { + return mNearDist; + } + + void ClearBuffer() override + { + assert(mMaskedHiZBuffer != nullptr); + + // Iterate through all depth tiles and clear to default values + for (int i = 0; i < mTilesWidth * mTilesHeight; i++) + { + mMaskedHiZBuffer[i].mMask = _mmw_setzero_epi32(); + + // Clear z0 to beyond infinity to ensure we never merge with clear data + mMaskedHiZBuffer[i].mZMin[0] = _mmw_set1_ps(-1.0f); +#if QUICK_MASK != 0 + // Clear z1 to nearest depth value as it is pushed back on each update + mMaskedHiZBuffer[i].mZMin[1] = _mmw_set1_ps(FLT_MAX); +#else + mMaskedHiZBuffer[i].mZMin[1] = _mmw_setzero_ps(); +#endif + } + +#if ENABLE_STATS != 0 + memset(&mStats, 0, sizeof(OcclusionCullingStatistics)); +#endif + +#if MOC_RECORDER_ENABLE != 0 + { + std::lock_guard lock( mRecorderMutex ); + if( mRecorder != nullptr ) mRecorder->RecordClearBuffer(); + } +#endif + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MergeBuffer + // Utility Function merges another MOC buffer into the existing one + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void MergeBuffer(MaskedOcclusionCulling* BufferB) override + { + assert(mMaskedHiZBuffer != nullptr); + + //// Iterate through all depth tiles and merge the 2 tiles + for (int i = 0; i < mTilesWidth * mTilesHeight; i++) + { + __mw *zMinB = ((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mZMin; + __mw *zMinA = mMaskedHiZBuffer[i].mZMin; + __mwi RastMaskB = ((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mMask; + +#if QUICK_MASK != 0 + // Clear z0 to beyond infinity to ensure we never merge with clear data + __mwi sign0 = _mmw_srai_epi32(simd_cast<__mwi>(zMinB[0]), 31); + // Only merge tiles that have data in zMinB[0], use the sign bit to determine if they are still in a clear state + sign0 = _mmw_cmpeq_epi32(sign0, SIMD_BITS_ZERO); + if (!_mmw_testz_epi32(sign0, sign0)) + { + STATS_ADD(mStats.mOccluders.mNumTilesMerged, 1); + zMinA[0] = _mmw_max_ps(zMinA[0], zMinB[0]); + + __mwi rastMask = mMaskedHiZBuffer[i].mMask; + __mwi deadLane = _mmw_cmpeq_epi32(rastMask, SIMD_BITS_ZERO); + // Mask out all subtiles failing the depth test (don't update these subtiles) + deadLane = _mmw_or_epi32(deadLane, _mmw_srai_epi32(simd_cast<__mwi>(_mmw_sub_ps(zMinA[1], zMinA[0])), 31)); + mMaskedHiZBuffer[i].mMask = _mmw_andnot_epi32(deadLane, rastMask); + } + + // Set 32bit value to -1 if any pixels are set incide the coverage mask for a subtile + __mwi LiveTile = _mmw_cmpeq_epi32(RastMaskB, SIMD_BITS_ZERO); + // invert to have bits set for clear subtiles + __mwi t0inv = _mmw_not_epi32(LiveTile); + // VPTEST sets the ZF flag if all the resulting bits are 0 (ie if all tiles are clear) + if (!_mmw_testz_epi32(t0inv, t0inv)) + { + STATS_ADD(mStats.mOccluders.mNumTilesMerged, 1); + UpdateTileQuick(i, RastMaskB, zMinB[1]); + } +#else + // Clear z0 to beyond infinity to ensure we never merge with clear data + __mwi sign1 = _mmw_srai_epi32(simd_cast<__mwi>(mMaskedHiZBuffer[i].mZMin[0]), 31); + // Only merge tiles that have data in zMinB[0], use the sign bit to determine if they are still in a clear state + sign1 = _mmw_cmpeq_epi32(sign1, SIMD_BITS_ZERO); + + // Set 32bit value to -1 if any pixels are set incide the coverage mask for a subtile + __mwi LiveTile1 = _mmw_cmpeq_epi32(mMaskedHiZBuffer[i].mMask, SIMD_BITS_ZERO); + // invert to have bits set for clear subtiles + __mwi t1inv = _mmw_not_epi32(LiveTile1); + // VPTEST sets the ZF flag if all the resulting bits are 0 (ie if all tiles are clear) + if (_mmw_testz_epi32(sign1, sign1) && _mmw_testz_epi32(t1inv, t1inv)) + { + mMaskedHiZBuffer[i].mMask = ((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mMask; + mMaskedHiZBuffer[i].mZMin[0] = zMinB[0]; + mMaskedHiZBuffer[i].mZMin[1] = zMinB[1]; + } + else + { + // Clear z0 to beyond infinity to ensure we never merge with clear data + __mwi sign0 = _mmw_srai_epi32(simd_cast<__mwi>(zMinB[0]), 31); + sign0 = _mmw_cmpeq_epi32(sign0, SIMD_BITS_ZERO); + // Only merge tiles that have data in zMinB[0], use the sign bit to determine if they are still in a clear state + if (!_mmw_testz_epi32(sign0, sign0)) + { + // build a mask for Zmin[0], full if the layer has been completed, or partial if tile is still partly filled. + // cant just use the completement of the mask, as tiles might not get updated by merge + __mwi sign1 = _mmw_srai_epi32(simd_cast<__mwi>(zMinB[1]), 31); + __mwi LayerMask0 = _mmw_not_epi32(sign1); + __mwi LayerMask1 = _mmw_not_epi32(((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mMask); + __mwi rastMask = _mmw_or_epi32(LayerMask0, LayerMask1); + + UpdateTileAccurate(i, rastMask, zMinB[0]); + } + + // Set 32bit value to -1 if any pixels are set incide the coverage mask for a subtile + __mwi LiveTile = _mmw_cmpeq_epi32(((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mMask, SIMD_BITS_ZERO); + // invert to have bits set for clear subtiles + __mwi t0inv = _mmw_not_epi32(LiveTile); + // VPTEST sets the ZF flag if all the resulting bits are 0 (ie if all tiles are clear) + if (!_mmw_testz_epi32(t0inv, t0inv)) + { + UpdateTileAccurate(i, ((MaskedOcclusionCullingPrivate*)BufferB)->mMaskedHiZBuffer[i].mMask, zMinB[1]); + } + + //if (_mmw_testz_epi32(sign0, sign0) && _mmw_testz_epi32(t0inv, t0inv)) + // STATS_ADD(mStats.mOccluders.mNumTilesMerged, 1); + + } + +#endif + } + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Polygon clipping functions + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FORCE_INLINE int ClipPolygon(__m128 *outVtx, __m128 *inVtx, const __m128 &plane, int n) const + { + __m128 p0 = inVtx[n - 1]; + __m128 dist0 = _mmx_dp4_ps(p0, plane); + + // Loop over all polygon edges and compute intersection with clip plane (if any) + int nout = 0; + for (int k = 0; k < n; k++) + { + __m128 p1 = inVtx[k]; + __m128 dist1 = _mmx_dp4_ps(p1, plane); + int dist0Neg = _mm_movemask_ps(dist0); + if (!dist0Neg) // dist0 > 0.0f + outVtx[nout++] = p0; + + // Edge intersects the clip plane if dist0 and dist1 have opposing signs + if (_mm_movemask_ps(_mm_xor_ps(dist0, dist1))) + { + // Always clip from the positive side to avoid T-junctions + if (!dist0Neg) + { + __m128 t = _mm_div_ps(dist0, _mm_sub_ps(dist0, dist1)); + outVtx[nout++] = _mmx_fmadd_ps(_mm_sub_ps(p1, p0), t, p0); + } + else + { + __m128 t = _mm_div_ps(dist1, _mm_sub_ps(dist1, dist0)); + outVtx[nout++] = _mmx_fmadd_ps(_mm_sub_ps(p0, p1), t, p1); + } + } + + dist0 = dist1; + p0 = p1; + } + return nout; + } + + template void TestClipPlane(__mw *vtxX, __mw *vtxY, __mw *vtxW, unsigned int &straddleMask, unsigned int &triMask, ClipPlanes clipPlaneMask) + { + straddleMask = 0; + // Skip masked clip planes + if (!(clipPlaneMask & CLIP_PLANE)) + return; + + // Evaluate all 3 vertices against the frustum plane + __mw planeDp[3]; + for (int i = 0; i < 3; ++i) + { + switch (CLIP_PLANE) + { + case ClipPlanes::CLIP_PLANE_LEFT: planeDp[i] = _mmw_add_ps(vtxW[i], vtxX[i]); break; + case ClipPlanes::CLIP_PLANE_RIGHT: planeDp[i] = _mmw_sub_ps(vtxW[i], vtxX[i]); break; + case ClipPlanes::CLIP_PLANE_BOTTOM: planeDp[i] = _mmw_add_ps(vtxW[i], vtxY[i]); break; + case ClipPlanes::CLIP_PLANE_TOP: planeDp[i] = _mmw_sub_ps(vtxW[i], vtxY[i]); break; + case ClipPlanes::CLIP_PLANE_NEAR: planeDp[i] = _mmw_sub_ps(vtxW[i], _mmw_set1_ps(mNearDist)); break; + } + } + + // Look at FP sign and determine if tri is inside, outside or straddles the frustum plane + __mw inside = _mmw_andnot_ps(planeDp[0], _mmw_andnot_ps(planeDp[1], _mmw_not_ps(planeDp[2]))); + __mw outside = _mmw_and_ps(planeDp[0], _mmw_and_ps(planeDp[1], planeDp[2])); + unsigned int inMask = (unsigned int)_mmw_movemask_ps(inside); + unsigned int outMask = (unsigned int)_mmw_movemask_ps(outside); + straddleMask = (~outMask) & (~inMask); + triMask &= ~outMask; + } + + FORCE_INLINE void ClipTriangleAndAddToBuffer(__mw *vtxX, __mw *vtxY, __mw *vtxW, __m128 *clippedTrisBuffer, int &clipWriteIdx, unsigned int &triMask, unsigned int triClipMask, ClipPlanes clipPlaneMask) + { + if (!triClipMask) + return; + + // Inside test all 3 triangle vertices against all active frustum planes + unsigned int straddleMask[5]; + TestClipPlane(vtxX, vtxY, vtxW, straddleMask[0], triMask, clipPlaneMask); + TestClipPlane(vtxX, vtxY, vtxW, straddleMask[1], triMask, clipPlaneMask); + TestClipPlane(vtxX, vtxY, vtxW, straddleMask[2], triMask, clipPlaneMask); + TestClipPlane(vtxX, vtxY, vtxW, straddleMask[3], triMask, clipPlaneMask); + TestClipPlane(vtxX, vtxY, vtxW, straddleMask[4], triMask, clipPlaneMask); + + // Clip triangle against straddling planes and add to the clipped triangle buffer + __m128 vtxBuf[2][8]; + +#if CLIPPING_PRESERVES_ORDER != 0 + unsigned int clipMask = triClipMask & triMask; + unsigned int clipAndStraddleMask = (straddleMask[0] | straddleMask[1] | straddleMask[2] | straddleMask[3] | straddleMask[4]) & clipMask; + // no clipping needed after all - early out + if (clipAndStraddleMask == 0) + return; + while( clipMask ) + { + // Find and setup next triangle to clip + unsigned int triIdx = find_clear_lsb(&clipMask); + unsigned int triBit = (1U << triIdx); + assert(triIdx < SIMD_LANES); + + int bufIdx = 0; + int nClippedVerts = 3; + for (int i = 0; i < 3; i++) + vtxBuf[0][i] = _mm_setr_ps(simd_f32(vtxX[i])[triIdx], simd_f32(vtxY[i])[triIdx], simd_f32(vtxW[i])[triIdx], 1.0f); + + // Clip triangle with straddling planes. + for (int i = 0; i < 5; ++i) + { + if ((straddleMask[i] & triBit) && (clipPlaneMask & (1 << i))) // <- second part maybe not needed? + { + nClippedVerts = ClipPolygon(vtxBuf[bufIdx ^ 1], vtxBuf[bufIdx], mCSFrustumPlanes[i], nClippedVerts); + bufIdx ^= 1; + } + } + + if (nClippedVerts >= 3) + { + // Write all triangles into the clip buffer and process them next loop iteration + clippedTrisBuffer[clipWriteIdx * 3 + 0] = vtxBuf[bufIdx][0]; + clippedTrisBuffer[clipWriteIdx * 3 + 1] = vtxBuf[bufIdx][1]; + clippedTrisBuffer[clipWriteIdx * 3 + 2] = vtxBuf[bufIdx][2]; + clipWriteIdx = (clipWriteIdx + 1) & (MAX_CLIPPED - 1); + for (int i = 2; i < nClippedVerts - 1; i++) + { + clippedTrisBuffer[clipWriteIdx * 3 + 0] = vtxBuf[bufIdx][0]; + clippedTrisBuffer[clipWriteIdx * 3 + 1] = vtxBuf[bufIdx][i]; + clippedTrisBuffer[clipWriteIdx * 3 + 2] = vtxBuf[bufIdx][i + 1]; + clipWriteIdx = (clipWriteIdx + 1) & (MAX_CLIPPED - 1); + } + } + } + // since all triangles were copied to clip buffer for next iteration, skip further processing + triMask = 0; +#else + unsigned int clipMask = (straddleMask[0] | straddleMask[1] | straddleMask[2] | straddleMask[3] | straddleMask[4]) & (triClipMask & triMask); + while (clipMask) + { + // Find and setup next triangle to clip + unsigned int triIdx = find_clear_lsb(&clipMask); + unsigned int triBit = (1U << triIdx); + assert(triIdx < SIMD_LANES); + + int bufIdx = 0; + int nClippedVerts = 3; + for (int i = 0; i < 3; i++) + vtxBuf[0][i] = _mm_setr_ps(simd_f32(vtxX[i])[triIdx], simd_f32(vtxY[i])[triIdx], simd_f32(vtxW[i])[triIdx], 1.0f); + + // Clip triangle with straddling planes. + for (int i = 0; i < 5; ++i) + { + if ((straddleMask[i] & triBit) && (clipPlaneMask & (1 << i))) + { + nClippedVerts = ClipPolygon(vtxBuf[bufIdx ^ 1], vtxBuf[bufIdx], mCSFrustumPlanes[i], nClippedVerts); + bufIdx ^= 1; + } + } + + if (nClippedVerts >= 3) + { + // Write the first triangle back into the list of currently processed triangles + for (int i = 0; i < 3; i++) + { + simd_f32(vtxX[i])[triIdx] = simd_f32(vtxBuf[bufIdx][i])[0]; + simd_f32(vtxY[i])[triIdx] = simd_f32(vtxBuf[bufIdx][i])[1]; + simd_f32(vtxW[i])[triIdx] = simd_f32(vtxBuf[bufIdx][i])[2]; + } + // Write the remaining triangles into the clip buffer and process them next loop iteration + for (int i = 2; i < nClippedVerts - 1; i++) + { + clippedTrisBuffer[clipWriteIdx * 3 + 0] = vtxBuf[bufIdx][0]; + clippedTrisBuffer[clipWriteIdx * 3 + 1] = vtxBuf[bufIdx][i]; + clippedTrisBuffer[clipWriteIdx * 3 + 2] = vtxBuf[bufIdx][i + 1]; + clipWriteIdx = (clipWriteIdx + 1) & (MAX_CLIPPED - 1); + } + } + else // Kill triangles that was removed by clipping + triMask &= ~triBit; + } +#endif + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Vertex transform & projection + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FORCE_INLINE void TransformVerts(__mw *vtxX, __mw *vtxY, __mw *vtxW, const float *modelToClipMatrix) + { + if (modelToClipMatrix != nullptr) + { + for (int i = 0; i < 3; ++i) + { + __mw tmpX, tmpY, tmpW; + tmpX = _mmw_fmadd_ps(vtxX[i], _mmw_set1_ps(modelToClipMatrix[0]), _mmw_fmadd_ps(vtxY[i], _mmw_set1_ps(modelToClipMatrix[4]), _mmw_fmadd_ps(vtxW[i], _mmw_set1_ps(modelToClipMatrix[8]), _mmw_set1_ps(modelToClipMatrix[12])))); + tmpY = _mmw_fmadd_ps(vtxX[i], _mmw_set1_ps(modelToClipMatrix[1]), _mmw_fmadd_ps(vtxY[i], _mmw_set1_ps(modelToClipMatrix[5]), _mmw_fmadd_ps(vtxW[i], _mmw_set1_ps(modelToClipMatrix[9]), _mmw_set1_ps(modelToClipMatrix[13])))); + tmpW = _mmw_fmadd_ps(vtxX[i], _mmw_set1_ps(modelToClipMatrix[3]), _mmw_fmadd_ps(vtxY[i], _mmw_set1_ps(modelToClipMatrix[7]), _mmw_fmadd_ps(vtxW[i], _mmw_set1_ps(modelToClipMatrix[11]), _mmw_set1_ps(modelToClipMatrix[15])))); + vtxX[i] = tmpX; vtxY[i] = tmpY; vtxW[i] = tmpW; + } + } + } + +#if PRECISE_COVERAGE != 0 + FORCE_INLINE void ProjectVertices(__mwi *ipVtxX, __mwi *ipVtxY, __mw *pVtxX, __mw *pVtxY, __mw *pVtxZ, const __mw *vtxX, const __mw *vtxY, const __mw *vtxW) + { +#if USE_D3D != 0 + static const int vertexOrder[] = {2, 1, 0}; +#else + static const int vertexOrder[] = {0, 1, 2}; +#endif + + // Project vertices and transform to screen space. Snap to sub-pixel coordinates with FP_BITS precision. + for (int i = 0; i < 3; i++) + { + int idx = vertexOrder[i]; + __mw rcpW = _mmw_div_ps(_mmw_set1_ps(1.0f), vtxW[i]); + __mw screenX = _mmw_fmadd_ps(_mmw_mul_ps(vtxX[i], mHalfWidth), rcpW, mCenterX); + __mw screenY = _mmw_fmadd_ps(_mmw_mul_ps(vtxY[i], mHalfHeight), rcpW, mCenterY); + ipVtxX[idx] = _mmw_cvtps_epi32(_mmw_mul_ps(screenX, _mmw_set1_ps(float(1 << FP_BITS)))); + ipVtxY[idx] = _mmw_cvtps_epi32(_mmw_mul_ps(screenY, _mmw_set1_ps(float(1 << FP_BITS)))); + pVtxX[idx] = _mmw_mul_ps(_mmw_cvtepi32_ps(ipVtxX[idx]), _mmw_set1_ps(FP_INV)); + pVtxY[idx] = _mmw_mul_ps(_mmw_cvtepi32_ps(ipVtxY[idx]), _mmw_set1_ps(FP_INV)); + pVtxZ[idx] = rcpW; + } + } +#else + FORCE_INLINE void ProjectVertices(__mw *pVtxX, __mw *pVtxY, __mw *pVtxZ, const __mw *vtxX, const __mw *vtxY, const __mw *vtxW) + { +#if USE_D3D != 0 + static const int vertexOrder[] = {2, 1, 0}; +#else + static const int vertexOrder[] = {0, 1, 2}; +#endif + // Project vertices and transform to screen space. Round to nearest integer pixel coordinate + for (int i = 0; i < 3; i++) + { + int idx = vertexOrder[i]; + __mw rcpW = _mmw_div_ps(_mmw_set1_ps(1.0f), vtxW[i]); + + // The rounding modes are set to match HW rasterization with OpenGL. In practice our samples are placed + // in the (1,0) corner of each pixel, while HW rasterizer uses (0.5, 0.5). We get (1,0) because of the + // floor used when interpolating along triangle edges. The rounding modes match an offset of (0.5, -0.5) + pVtxX[idx] = _mmw_ceil_ps(_mmw_fmadd_ps(_mmw_mul_ps(vtxX[i], mHalfWidth), rcpW, mCenterX)); + pVtxY[idx] = _mmw_floor_ps(_mmw_fmadd_ps(_mmw_mul_ps(vtxY[i], mHalfHeight), rcpW, mCenterY)); + pVtxZ[idx] = rcpW; + } + } +#endif + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Common SSE/AVX input assembly functions, note that there are specialized gathers for the general case in the SSE/AVX specific files + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FORCE_INLINE void GatherVerticesFast(__mw *vtxX, __mw *vtxY, __mw *vtxW, const float *inVtx, const unsigned int *inTrisPtr, int numLanes) + { + // This function assumes that the vertex layout is four packed x, y, z, w-values. + // Since the layout is known we can get some additional performance by using a + // more optimized gather strategy. + assert(numLanes >= 1); + + // Gather vertices + __mw v[4], swz[4]; + for (int i = 0; i < 3; i++) + { + // Load 4 (x,y,z,w) vectors per SSE part of the SIMD register (so 4 vectors for SSE, 8 vectors for AVX) + // this fetch uses templates to unroll the loop + VtxFetch4(v, inTrisPtr, i, inVtx, numLanes); + + // Transpose each individual SSE part of the SSE/AVX register (similar to _MM_TRANSPOSE4_PS) + swz[0] = _mmw_shuffle_ps(v[0], v[1], 0x44); + swz[2] = _mmw_shuffle_ps(v[0], v[1], 0xEE); + swz[1] = _mmw_shuffle_ps(v[2], v[3], 0x44); + swz[3] = _mmw_shuffle_ps(v[2], v[3], 0xEE); + + vtxX[i] = _mmw_shuffle_ps(swz[0], swz[1], 0x88); + vtxY[i] = _mmw_shuffle_ps(swz[0], swz[1], 0xDD); + vtxW[i] = _mmw_shuffle_ps(swz[2], swz[3], 0xDD); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Rasterization functions + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FORCE_INLINE void ComputeBoundingBox(__mwi &bbminX, __mwi &bbminY, __mwi &bbmaxX, __mwi &bbmaxY, const __mw *vX, const __mw *vY, const ScissorRect *scissor) + { + static const __mwi SIMD_PAD_W_MASK = _mmw_set1_epi32(~(TILE_WIDTH - 1)); + static const __mwi SIMD_PAD_H_MASK = _mmw_set1_epi32(~(TILE_HEIGHT - 1)); + + // Find Min/Max vertices + bbminX = _mmw_cvttps_epi32(_mmw_min_ps(vX[0], _mmw_min_ps(vX[1], vX[2]))); + bbminY = _mmw_cvttps_epi32(_mmw_min_ps(vY[0], _mmw_min_ps(vY[1], vY[2]))); + bbmaxX = _mmw_cvttps_epi32(_mmw_max_ps(vX[0], _mmw_max_ps(vX[1], vX[2]))); + bbmaxY = _mmw_cvttps_epi32(_mmw_max_ps(vY[0], _mmw_max_ps(vY[1], vY[2]))); + + // Clamp to tile boundaries + bbminX = _mmw_and_epi32(bbminX, SIMD_PAD_W_MASK); + bbmaxX = _mmw_and_epi32(_mmw_add_epi32(bbmaxX, _mmw_set1_epi32(TILE_WIDTH)), SIMD_PAD_W_MASK); + bbminY = _mmw_and_epi32(bbminY, SIMD_PAD_H_MASK); + bbmaxY = _mmw_and_epi32(_mmw_add_epi32(bbmaxY, _mmw_set1_epi32(TILE_HEIGHT)), SIMD_PAD_H_MASK); + + // Clip to scissor + bbminX = _mmw_max_epi32(bbminX, _mmw_set1_epi32(scissor->mMinX)); + bbmaxX = _mmw_min_epi32(bbmaxX, _mmw_set1_epi32(scissor->mMaxX)); + bbminY = _mmw_max_epi32(bbminY, _mmw_set1_epi32(scissor->mMinY)); + bbmaxY = _mmw_min_epi32(bbmaxY, _mmw_set1_epi32(scissor->mMaxY)); + } + +#if PRECISE_COVERAGE != 0 + FORCE_INLINE void SortVertices(__mwi *vX, __mwi *vY) + { + // Rotate the triangle in the winding order until v0 is the vertex with lowest Y value + for (int i = 0; i < 2; i++) + { + __mwi ey1 = _mmw_sub_epi32(vY[1], vY[0]); + __mwi ey2 = _mmw_sub_epi32(vY[2], vY[0]); + __mwi swapMask = _mmw_or_epi32(_mmw_or_epi32(ey1, ey2), _mmw_cmpeq_epi32(simd_cast<__mwi>(ey2), SIMD_BITS_ZERO)); + __mwi sX, sY; + sX = _mmw_blendv_epi32(vX[2], vX[0], swapMask); + vX[0] = _mmw_blendv_epi32(vX[0], vX[1], swapMask); + vX[1] = _mmw_blendv_epi32(vX[1], vX[2], swapMask); + vX[2] = sX; + sY = _mmw_blendv_epi32(vY[2], vY[0], swapMask); + vY[0] = _mmw_blendv_epi32(vY[0], vY[1], swapMask); + vY[1] = _mmw_blendv_epi32(vY[1], vY[2], swapMask); + vY[2] = sY; + } + } + + FORCE_INLINE int CullBackfaces(__mwi *ipVtxX, __mwi *ipVtxY, __mw *pVtxX, __mw *pVtxY, __mw *pVtxZ, const __mw &ccwMask, BackfaceWinding bfWinding) + { + // Reverse vertex order if non cw faces are considered front facing (rasterizer code requires CCW order) + if (!(bfWinding & BACKFACE_CW)) + { + __mw tmpX, tmpY, tmpZ; + __mwi itmpX, itmpY; + itmpX = _mmw_blendv_epi32(ipVtxX[2], ipVtxX[0], simd_cast<__mwi>(ccwMask)); + itmpY = _mmw_blendv_epi32(ipVtxY[2], ipVtxY[0], simd_cast<__mwi>(ccwMask)); + tmpX = _mmw_blendv_ps(pVtxX[2], pVtxX[0], ccwMask); + tmpY = _mmw_blendv_ps(pVtxY[2], pVtxY[0], ccwMask); + tmpZ = _mmw_blendv_ps(pVtxZ[2], pVtxZ[0], ccwMask); + ipVtxX[2] = _mmw_blendv_epi32(ipVtxX[0], ipVtxX[2], simd_cast<__mwi>(ccwMask)); + ipVtxY[2] = _mmw_blendv_epi32(ipVtxY[0], ipVtxY[2], simd_cast<__mwi>(ccwMask)); + pVtxX[2] = _mmw_blendv_ps(pVtxX[0], pVtxX[2], ccwMask); + pVtxY[2] = _mmw_blendv_ps(pVtxY[0], pVtxY[2], ccwMask); + pVtxZ[2] = _mmw_blendv_ps(pVtxZ[0], pVtxZ[2], ccwMask); + ipVtxX[0] = itmpX; + ipVtxY[0] = itmpY; + pVtxX[0] = tmpX; + pVtxY[0] = tmpY; + pVtxZ[0] = tmpZ; + } + + // Return a lane mask with all front faces set + return ((bfWinding & BACKFACE_CCW) ? 0 : _mmw_movemask_ps(ccwMask)) | ((bfWinding & BACKFACE_CW) ? 0 : ~_mmw_movemask_ps(ccwMask)); + } +#else + FORCE_INLINE void SortVertices(__mw *vX, __mw *vY) + { + // Rotate the triangle in the winding order until v0 is the vertex with lowest Y value + for (int i = 0; i < 2; i++) + { + __mw ey1 = _mmw_sub_ps(vY[1], vY[0]); + __mw ey2 = _mmw_sub_ps(vY[2], vY[0]); + __mw swapMask = _mmw_or_ps(_mmw_or_ps(ey1, ey2), simd_cast<__mw>(_mmw_cmpeq_epi32(simd_cast<__mwi>(ey2), SIMD_BITS_ZERO))); + __mw sX, sY; + sX = _mmw_blendv_ps(vX[2], vX[0], swapMask); + vX[0] = _mmw_blendv_ps(vX[0], vX[1], swapMask); + vX[1] = _mmw_blendv_ps(vX[1], vX[2], swapMask); + vX[2] = sX; + sY = _mmw_blendv_ps(vY[2], vY[0], swapMask); + vY[0] = _mmw_blendv_ps(vY[0], vY[1], swapMask); + vY[1] = _mmw_blendv_ps(vY[1], vY[2], swapMask); + vY[2] = sY; + } + } + + FORCE_INLINE int CullBackfaces(__mw *pVtxX, __mw *pVtxY, __mw *pVtxZ, const __mw &ccwMask, BackfaceWinding bfWinding) + { + // Reverse vertex order if non cw faces are considered front facing (rasterizer code requires CCW order) + if (!(bfWinding & BACKFACE_CW)) + { + __mw tmpX, tmpY, tmpZ; + tmpX = _mmw_blendv_ps(pVtxX[2], pVtxX[0], ccwMask); + tmpY = _mmw_blendv_ps(pVtxY[2], pVtxY[0], ccwMask); + tmpZ = _mmw_blendv_ps(pVtxZ[2], pVtxZ[0], ccwMask); + pVtxX[2] = _mmw_blendv_ps(pVtxX[0], pVtxX[2], ccwMask); + pVtxY[2] = _mmw_blendv_ps(pVtxY[0], pVtxY[2], ccwMask); + pVtxZ[2] = _mmw_blendv_ps(pVtxZ[0], pVtxZ[2], ccwMask); + pVtxX[0] = tmpX; + pVtxY[0] = tmpY; + pVtxZ[0] = tmpZ; + } + + // Return a lane mask with all front faces set + return ((bfWinding & BACKFACE_CCW) ? 0 : _mmw_movemask_ps(ccwMask)) | ((bfWinding & BACKFACE_CW) ? 0 : ~_mmw_movemask_ps(ccwMask)); + } +#endif + + FORCE_INLINE void ComputeDepthPlane(const __mw *pVtxX, const __mw *pVtxY, const __mw *pVtxZ, __mw &zPixelDx, __mw &zPixelDy) const + { + // Setup z(x,y) = z0 + dx*x + dy*y screen space depth plane equation + __mw x2 = _mmw_sub_ps(pVtxX[2], pVtxX[0]); + __mw x1 = _mmw_sub_ps(pVtxX[1], pVtxX[0]); + __mw y1 = _mmw_sub_ps(pVtxY[1], pVtxY[0]); + __mw y2 = _mmw_sub_ps(pVtxY[2], pVtxY[0]); + __mw z1 = _mmw_sub_ps(pVtxZ[1], pVtxZ[0]); + __mw z2 = _mmw_sub_ps(pVtxZ[2], pVtxZ[0]); + __mw d = _mmw_div_ps(_mmw_set1_ps(1.0f), _mmw_fmsub_ps(x1, y2, _mmw_mul_ps(y1, x2))); + zPixelDx = _mmw_mul_ps(_mmw_fmsub_ps(z1, y2, _mmw_mul_ps(y1, z2)), d); + zPixelDy = _mmw_mul_ps(_mmw_fmsub_ps(x1, z2, _mmw_mul_ps(z1, x2)), d); + } + + FORCE_INLINE void UpdateTileQuick(int tileIdx, const __mwi &coverage, const __mw &zTriv) + { + // Update heuristic used in the paper "Masked Software Occlusion Culling", + // good balance between performance and accuracy + STATS_ADD(mStats.mOccluders.mNumTilesUpdated, 1); + assert(tileIdx >= 0 && tileIdx < mTilesWidth*mTilesHeight); + + __mwi mask = mMaskedHiZBuffer[tileIdx].mMask; + __mw *zMin = mMaskedHiZBuffer[tileIdx].mZMin; + + // Swizzle coverage mask to 8x4 subtiles and test if any subtiles are not covered at all + __mwi rastMask = coverage; + __mwi deadLane = _mmw_cmpeq_epi32(rastMask, SIMD_BITS_ZERO); + + // Mask out all subtiles failing the depth test (don't update these subtiles) + deadLane = _mmw_or_epi32(deadLane, _mmw_srai_epi32(simd_cast<__mwi>(_mmw_sub_ps(zTriv, zMin[0])), 31)); + rastMask = _mmw_andnot_epi32(deadLane, rastMask); + + // Use distance heuristic to discard layer 1 if incoming triangle is significantly nearer to observer + // than the buffer contents. See Section 3.2 in "Masked Software Occlusion Culling" + __mwi coveredLane = _mmw_cmpeq_epi32(rastMask, SIMD_BITS_ONE); + __mw diff = _mmw_fmsub_ps(zMin[1], _mmw_set1_ps(2.0f), _mmw_add_ps(zTriv, zMin[0])); + __mwi discardLayerMask = _mmw_andnot_epi32(deadLane, _mmw_or_epi32(_mmw_srai_epi32(simd_cast<__mwi>(diff), 31), coveredLane)); + + // Update the mask with incoming triangle coverage + mask = _mmw_or_epi32(_mmw_andnot_epi32(discardLayerMask, mask), rastMask); + + __mwi maskFull = _mmw_cmpeq_epi32(mask, SIMD_BITS_ONE); + + // Compute new value for zMin[1]. This has one of four outcomes: zMin[1] = min(zMin[1], zTriv), zMin[1] = zTriv, + // zMin[1] = FLT_MAX or unchanged, depending on if the layer is updated, discarded, fully covered, or not updated + __mw opA = _mmw_blendv_ps(zTriv, zMin[1], simd_cast<__mw>(deadLane)); + __mw opB = _mmw_blendv_ps(zMin[1], zTriv, simd_cast<__mw>(discardLayerMask)); + __mw z1min = _mmw_min_ps(opA, opB); + zMin[1] = _mmw_blendv_ps(z1min, _mmw_set1_ps(FLT_MAX), simd_cast<__mw>(maskFull)); + + // Propagate zMin[1] back to zMin[0] if tile was fully covered, and update the mask + zMin[0] = _mmw_blendv_ps(zMin[0], z1min, simd_cast<__mw>(maskFull)); + mMaskedHiZBuffer[tileIdx].mMask = _mmw_andnot_epi32(maskFull, mask); + } + + FORCE_INLINE void UpdateTileAccurate(int tileIdx, const __mwi &coverage, const __mw &zTriv) + { + assert(tileIdx >= 0 && tileIdx < mTilesWidth*mTilesHeight); + + __mw *zMin = mMaskedHiZBuffer[tileIdx].mZMin; + __mwi &mask = mMaskedHiZBuffer[tileIdx].mMask; + + // Swizzle coverage mask to 8x4 subtiles + __mwi rastMask = coverage; + + // Perform individual depth tests with layer 0 & 1 and mask out all failing pixels + __mw sdist0 = _mmw_sub_ps(zMin[0], zTriv); + __mw sdist1 = _mmw_sub_ps(zMin[1], zTriv); + __mwi sign0 = _mmw_srai_epi32(simd_cast<__mwi>(sdist0), 31); + __mwi sign1 = _mmw_srai_epi32(simd_cast<__mwi>(sdist1), 31); + __mwi triMask = _mmw_and_epi32(rastMask, _mmw_or_epi32(_mmw_andnot_epi32(mask, sign0), _mmw_and_epi32(mask, sign1))); + + // Early out if no pixels survived the depth test (this test is more accurate than + // the early culling test in TraverseScanline()) + __mwi t0 = _mmw_cmpeq_epi32(triMask, SIMD_BITS_ZERO); + __mwi t0inv = _mmw_not_epi32(t0); + if (_mmw_testz_epi32(t0inv, t0inv)) + return; + + STATS_ADD(mStats.mOccluders.mNumTilesUpdated, 1); + + __mw zTri = _mmw_blendv_ps(zTriv, zMin[0], simd_cast<__mw>(t0)); + + // Test if incoming triangle completely overwrites layer 0 or 1 + __mwi layerMask0 = _mmw_andnot_epi32(triMask, _mmw_not_epi32(mask)); + __mwi layerMask1 = _mmw_andnot_epi32(triMask, mask); + __mwi lm0 = _mmw_cmpeq_epi32(layerMask0, SIMD_BITS_ZERO); + __mwi lm1 = _mmw_cmpeq_epi32(layerMask1, SIMD_BITS_ZERO); + __mw z0 = _mmw_blendv_ps(zMin[0], zTri, simd_cast<__mw>(lm0)); + __mw z1 = _mmw_blendv_ps(zMin[1], zTri, simd_cast<__mw>(lm1)); + + // Compute distances used for merging heuristic + __mw d0 = _mmw_abs_ps(sdist0); + __mw d1 = _mmw_abs_ps(sdist1); + __mw d2 = _mmw_abs_ps(_mmw_sub_ps(z0, z1)); + + // Find minimum distance + __mwi c01 = simd_cast<__mwi>(_mmw_sub_ps(d0, d1)); + __mwi c02 = simd_cast<__mwi>(_mmw_sub_ps(d0, d2)); + __mwi c12 = simd_cast<__mwi>(_mmw_sub_ps(d1, d2)); + // Two tests indicating which layer the incoming triangle will merge with or + // overwrite. d0min indicates that the triangle will overwrite layer 0, and + // d1min flags that the triangle will overwrite layer 1. + __mwi d0min = _mmw_or_epi32(_mmw_and_epi32(c01, c02), _mmw_or_epi32(lm0, t0)); + __mwi d1min = _mmw_andnot_epi32(d0min, _mmw_or_epi32(c12, lm1)); + + /////////////////////////////////////////////////////////////////////////////// + // Update depth buffer entry. NOTE: we always merge into layer 0, so if the + // triangle should be merged with layer 1, we first swap layer 0 & 1 and then + // merge into layer 0. + /////////////////////////////////////////////////////////////////////////////// + + // Update mask based on which layer the triangle overwrites or was merged into + __mw inner = _mmw_blendv_ps(simd_cast<__mw>(triMask), simd_cast<__mw>(layerMask1), simd_cast<__mw>(d0min)); + mask = simd_cast<__mwi>(_mmw_blendv_ps(inner, simd_cast<__mw>(layerMask0), simd_cast<__mw>(d1min))); + + // Update the zMin[0] value. There are four outcomes: overwrite with layer 1, + // merge with layer 1, merge with zTri or overwrite with layer 1 and then merge + // with zTri. + __mw e0 = _mmw_blendv_ps(z0, z1, simd_cast<__mw>(d1min)); + __mw e1 = _mmw_blendv_ps(z1, zTri, simd_cast<__mw>(_mmw_or_epi32(d1min, d0min))); + zMin[0] = _mmw_min_ps(e0, e1); + + // Update the zMin[1] value. There are three outcomes: keep current value, + // overwrite with zTri, or overwrite with z1 + __mw z1t = _mmw_blendv_ps(zTri, z1, simd_cast<__mw>(d0min)); + zMin[1] = _mmw_blendv_ps(z1t, z0, simd_cast<__mw>(d1min)); + } + + template + FORCE_INLINE int TraverseScanline(int leftOffset, int rightOffset, int tileIdx, int rightEvent, int leftEvent, const __mwi *events, const __mw &zTriMin, const __mw &zTriMax, const __mw &iz0, float zx) + { + // Floor edge events to integer pixel coordinates (shift out fixed point bits) + int eventOffset = leftOffset << TILE_WIDTH_SHIFT; + __mwi right[NRIGHT], left[NLEFT]; + for (int i = 0; i < NRIGHT; ++i) + right[i] = _mmw_max_epi32(_mmw_sub_epi32(_mmw_srai_epi32(events[rightEvent + i], FP_BITS), _mmw_set1_epi32(eventOffset)), SIMD_BITS_ZERO); + for (int i = 0; i < NLEFT; ++i) + left[i] = _mmw_max_epi32(_mmw_sub_epi32(_mmw_srai_epi32(events[leftEvent - i], FP_BITS), _mmw_set1_epi32(eventOffset)), SIMD_BITS_ZERO); + + __mw z0 = _mmw_add_ps(iz0, _mmw_set1_ps(zx*leftOffset)); + int tileIdxEnd = tileIdx + rightOffset; + tileIdx += leftOffset; + for (;;) + { + if (TEST_Z) + STATS_ADD(mStats.mOccludees.mNumTilesTraversed, 1); + else + STATS_ADD(mStats.mOccluders.mNumTilesTraversed, 1); + + // Perform a coarse test to quickly discard occluded tiles +#if QUICK_MASK != 0 + // Only use the reference layer (layer 0) to cull as it is always conservative + __mw zMinBuf = mMaskedHiZBuffer[tileIdx].mZMin[0]; +#else + // Compute zMin for the overlapped layers + __mwi mask = mMaskedHiZBuffer[tileIdx].mMask; + __mw zMin0 = _mmw_blendv_ps(mMaskedHiZBuffer[tileIdx].mZMin[0], mMaskedHiZBuffer[tileIdx].mZMin[1], simd_cast<__mw>(_mmw_cmpeq_epi32(mask, _mmw_set1_epi32(~0)))); + __mw zMin1 = _mmw_blendv_ps(mMaskedHiZBuffer[tileIdx].mZMin[1], mMaskedHiZBuffer[tileIdx].mZMin[0], simd_cast<__mw>(_mmw_cmpeq_epi32(mask, _mmw_setzero_epi32()))); + __mw zMinBuf = _mmw_min_ps(zMin0, zMin1); +#endif + __mw dist0 = _mmw_sub_ps(zTriMax, zMinBuf); + if (_mmw_movemask_ps(dist0) != SIMD_ALL_LANES_MASK) + { + // Compute coverage mask for entire 32xN using shift operations + __mwi accumulatedMask = _mmw_sllv_ones(left[0]); + for (int i = 1; i < NLEFT; ++i) + accumulatedMask = _mmw_and_epi32(accumulatedMask, _mmw_sllv_ones(left[i])); + for (int i = 0; i < NRIGHT; ++i) + accumulatedMask = _mmw_andnot_epi32(_mmw_sllv_ones(right[i]), accumulatedMask); + + if (TEST_Z) + { + // Perform a conservative visibility test (test zMax against buffer for each covered 8x4 subtile) + __mw zSubTileMax = _mmw_min_ps(z0, zTriMax); + __mwi zPass = simd_cast<__mwi>(_mmw_cmpge_ps(zSubTileMax, zMinBuf)); + + __mwi rastMask = _mmw_transpose_epi8(accumulatedMask); + __mwi deadLane = _mmw_cmpeq_epi32(rastMask, SIMD_BITS_ZERO); + zPass = _mmw_andnot_epi32(deadLane, zPass); + + if (!_mmw_testz_epi32(zPass, zPass)) + return CullingResult::VISIBLE; + } + else + { + // Compute interpolated min for each 8x4 subtile and update the masked hierarchical z buffer entry + __mw zSubTileMin = _mmw_max_ps(z0, zTriMin); +#if QUICK_MASK != 0 + UpdateTileQuick(tileIdx, _mmw_transpose_epi8(accumulatedMask), zSubTileMin); +#else + UpdateTileAccurate(tileIdx, _mmw_transpose_epi8(accumulatedMask), zSubTileMin); +#endif + } + } + + // Update buffer address, interpolate z and edge events + tileIdx++; + if (tileIdx >= tileIdxEnd) + break; + z0 = _mmw_add_ps(z0, _mmw_set1_ps(zx)); + for (int i = 0; i < NRIGHT; ++i) + right[i] = _mmw_subs_epu16(right[i], SIMD_TILE_WIDTH); // Trick, use sub saturated to avoid checking against < 0 for shift (values should fit in 16 bits) + for (int i = 0; i < NLEFT; ++i) + left[i] = _mmw_subs_epu16(left[i], SIMD_TILE_WIDTH); + } + + return TEST_Z ? CullingResult::OCCLUDED : CullingResult::VISIBLE; + } + + + template +#if PRECISE_COVERAGE != 0 + FORCE_INLINE int RasterizeTriangle(unsigned int triIdx, int bbWidth, int tileRowIdx, int tileMidRowIdx, int tileEndRowIdx, const __mwi *eventStart, const __mw *slope, const __mwi *slopeTileDelta, const __mw &zTriMin, const __mw &zTriMax, __mw &z0, float zx, float zy, const __mwi *edgeY, const __mwi *absEdgeX, const __mwi *slopeSign, const __mwi *eventStartRemainder, const __mwi *slopeTileRemainder) +#else + FORCE_INLINE int RasterizeTriangle(unsigned int triIdx, int bbWidth, int tileRowIdx, int tileMidRowIdx, int tileEndRowIdx, const __mwi *eventStart, const __mwi *slope, const __mwi *slopeTileDelta, const __mw &zTriMin, const __mw &zTriMax, __mw &z0, float zx, float zy) +#endif + { + if (TEST_Z) + STATS_ADD(mStats.mOccludees.mNumRasterizedTriangles, 1); + else + STATS_ADD(mStats.mOccluders.mNumRasterizedTriangles, 1); + + int cullResult; + +#if PRECISE_COVERAGE != 0 + #define LEFT_EDGE_BIAS -1 + #define RIGHT_EDGE_BIAS 1 + #define UPDATE_TILE_EVENTS_Y(i) \ + triEventRemainder[i] = _mmw_sub_epi32(triEventRemainder[i], triSlopeTileRemainder[i]); \ + __mwi overflow##i = _mmw_srai_epi32(triEventRemainder[i], 31); \ + triEventRemainder[i] = _mmw_add_epi32(triEventRemainder[i], _mmw_and_epi32(overflow##i, triEdgeY[i])); \ + triEvent[i] = _mmw_add_epi32(triEvent[i], _mmw_add_epi32(triSlopeTileDelta[i], _mmw_and_epi32(overflow##i, triSlopeSign[i]))) + + __mwi triEvent[3], triSlopeSign[3], triSlopeTileDelta[3], triEdgeY[3], triSlopeTileRemainder[3], triEventRemainder[3]; + for (int i = 0; i < 3; ++i) + { + triSlopeSign[i] = _mmw_set1_epi32(simd_i32(slopeSign[i])[triIdx]); + triSlopeTileDelta[i] = _mmw_set1_epi32(simd_i32(slopeTileDelta[i])[triIdx]); + triEdgeY[i] = _mmw_set1_epi32(simd_i32(edgeY[i])[triIdx]); + triSlopeTileRemainder[i] = _mmw_set1_epi32(simd_i32(slopeTileRemainder[i])[triIdx]); + + __mw triSlope = _mmw_set1_ps(simd_f32(slope[i])[triIdx]); + __mwi triAbsEdgeX = _mmw_set1_epi32(simd_i32(absEdgeX[i])[triIdx]); + __mwi triStartRemainder = _mmw_set1_epi32(simd_i32(eventStartRemainder[i])[triIdx]); + __mwi triEventStart = _mmw_set1_epi32(simd_i32(eventStart[i])[triIdx]); + + __mwi scanlineDelta = _mmw_cvttps_epi32(_mmw_mul_ps(triSlope, SIMD_LANE_YCOORD_F)); + __mwi scanlineSlopeRemainder = _mmw_sub_epi32(_mmw_mullo_epi32(triAbsEdgeX, SIMD_LANE_YCOORD_I), _mmw_mullo_epi32(_mmw_abs_epi32(scanlineDelta), triEdgeY[i])); + + triEventRemainder[i] = _mmw_sub_epi32(triStartRemainder, scanlineSlopeRemainder); + __mwi overflow = _mmw_srai_epi32(triEventRemainder[i], 31); + triEventRemainder[i] = _mmw_add_epi32(triEventRemainder[i], _mmw_and_epi32(overflow, triEdgeY[i])); + triEvent[i] = _mmw_add_epi32(_mmw_add_epi32(triEventStart, scanlineDelta), _mmw_and_epi32(overflow, triSlopeSign[i])); + } + +#else + #define LEFT_EDGE_BIAS 0 + #define RIGHT_EDGE_BIAS 0 + #define UPDATE_TILE_EVENTS_Y(i) triEvent[i] = _mmw_add_epi32(triEvent[i], triSlopeTileDelta[i]); + + // Get deltas used to increment edge events each time we traverse one scanline of tiles + __mwi triSlopeTileDelta[3]; + triSlopeTileDelta[0] = _mmw_set1_epi32(simd_i32(slopeTileDelta[0])[triIdx]); + triSlopeTileDelta[1] = _mmw_set1_epi32(simd_i32(slopeTileDelta[1])[triIdx]); + triSlopeTileDelta[2] = _mmw_set1_epi32(simd_i32(slopeTileDelta[2])[triIdx]); + + // Setup edge events for first batch of SIMD_LANES scanlines + __mwi triEvent[3]; + triEvent[0] = _mmw_add_epi32(_mmw_set1_epi32(simd_i32(eventStart[0])[triIdx]), _mmw_mullo_epi32(SIMD_LANE_IDX, _mmw_set1_epi32(simd_i32(slope[0])[triIdx]))); + triEvent[1] = _mmw_add_epi32(_mmw_set1_epi32(simd_i32(eventStart[1])[triIdx]), _mmw_mullo_epi32(SIMD_LANE_IDX, _mmw_set1_epi32(simd_i32(slope[1])[triIdx]))); + triEvent[2] = _mmw_add_epi32(_mmw_set1_epi32(simd_i32(eventStart[2])[triIdx]), _mmw_mullo_epi32(SIMD_LANE_IDX, _mmw_set1_epi32(simd_i32(slope[2])[triIdx]))); +#endif + + // For big triangles track start & end tile for each scanline and only traverse the valid region + int startDelta, endDelta, topDelta, startEvent, endEvent, topEvent; + if (TIGHT_TRAVERSAL) + { + startDelta = simd_i32(slopeTileDelta[2])[triIdx] + LEFT_EDGE_BIAS; + endDelta = simd_i32(slopeTileDelta[0])[triIdx] + RIGHT_EDGE_BIAS; + topDelta = simd_i32(slopeTileDelta[1])[triIdx] + (MID_VTX_RIGHT ? RIGHT_EDGE_BIAS : LEFT_EDGE_BIAS); + + // Compute conservative bounds for the edge events over a 32xN tile + startEvent = simd_i32(eventStart[2])[triIdx] + min(0, startDelta); + endEvent = simd_i32(eventStart[0])[triIdx] + max(0, endDelta) + (TILE_WIDTH << FP_BITS); + if (MID_VTX_RIGHT) + topEvent = simd_i32(eventStart[1])[triIdx] + max(0, topDelta) + (TILE_WIDTH << FP_BITS); + else + topEvent = simd_i32(eventStart[1])[triIdx] + min(0, topDelta); + } + + if (tileRowIdx <= tileMidRowIdx) + { + int tileStopIdx = min(tileEndRowIdx, tileMidRowIdx); + // Traverse the bottom half of the triangle + while (tileRowIdx < tileStopIdx) + { + int start = 0, end = bbWidth; + if (TIGHT_TRAVERSAL) + { + // Compute tighter start and endpoints to avoid traversing empty space + start = max(0, min(bbWidth - 1, startEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + end = min(bbWidth, ((int)endEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + startEvent += startDelta; + endEvent += endDelta; + } + + // Traverse the scanline and update the masked hierarchical z buffer + cullResult = TraverseScanline(start, end, tileRowIdx, 0, 2, triEvent, zTriMin, zTriMax, z0, zx); + + if (TEST_Z && cullResult == CullingResult::VISIBLE) // Early out if performing occlusion query + return CullingResult::VISIBLE; + + // move to the next scanline of tiles, update edge events and interpolate z + tileRowIdx += mTilesWidth; + z0 = _mmw_add_ps(z0, _mmw_set1_ps(zy)); + UPDATE_TILE_EVENTS_Y(0); + UPDATE_TILE_EVENTS_Y(2); + } + + // Traverse the middle scanline of tiles. We must consider all three edges only in this region + if (tileRowIdx < tileEndRowIdx) + { + int start = 0, end = bbWidth; + if (TIGHT_TRAVERSAL) + { + // Compute tighter start and endpoints to avoid traversing lots of empty space + start = max(0, min(bbWidth - 1, startEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + end = min(bbWidth, ((int)endEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + + // Switch the traversal start / end to account for the upper side edge + endEvent = MID_VTX_RIGHT ? topEvent : endEvent; + endDelta = MID_VTX_RIGHT ? topDelta : endDelta; + startEvent = MID_VTX_RIGHT ? startEvent : topEvent; + startDelta = MID_VTX_RIGHT ? startDelta : topDelta; + startEvent += startDelta; + endEvent += endDelta; + } + + // Traverse the scanline and update the masked hierarchical z buffer. + if (MID_VTX_RIGHT) + cullResult = TraverseScanline(start, end, tileRowIdx, 0, 2, triEvent, zTriMin, zTriMax, z0, zx); + else + cullResult = TraverseScanline(start, end, tileRowIdx, 0, 2, triEvent, zTriMin, zTriMax, z0, zx); + + if (TEST_Z && cullResult == CullingResult::VISIBLE) // Early out if performing occlusion query + return CullingResult::VISIBLE; + + tileRowIdx += mTilesWidth; + } + + // Traverse the top half of the triangle + if (tileRowIdx < tileEndRowIdx) + { + // move to the next scanline of tiles, update edge events and interpolate z + z0 = _mmw_add_ps(z0, _mmw_set1_ps(zy)); + int i0 = MID_VTX_RIGHT + 0; + int i1 = MID_VTX_RIGHT + 1; + UPDATE_TILE_EVENTS_Y(i0); + UPDATE_TILE_EVENTS_Y(i1); + for (;;) + { + int start = 0, end = bbWidth; + if (TIGHT_TRAVERSAL) + { + // Compute tighter start and endpoints to avoid traversing lots of empty space + start = max(0, min(bbWidth - 1, startEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + end = min(bbWidth, ((int)endEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + startEvent += startDelta; + endEvent += endDelta; + } + + // Traverse the scanline and update the masked hierarchical z buffer + cullResult = TraverseScanline(start, end, tileRowIdx, MID_VTX_RIGHT + 0, MID_VTX_RIGHT + 1, triEvent, zTriMin, zTriMax, z0, zx); + + if (TEST_Z && cullResult == CullingResult::VISIBLE) // Early out if performing occlusion query + return CullingResult::VISIBLE; + + // move to the next scanline of tiles, update edge events and interpolate z + tileRowIdx += mTilesWidth; + if (tileRowIdx >= tileEndRowIdx) + break; + z0 = _mmw_add_ps(z0, _mmw_set1_ps(zy)); + UPDATE_TILE_EVENTS_Y(i0); + UPDATE_TILE_EVENTS_Y(i1); + } + } + } + else + { + if (TIGHT_TRAVERSAL) + { + // For large triangles, switch the traversal start / end to account for the upper side edge + endEvent = MID_VTX_RIGHT ? topEvent : endEvent; + endDelta = MID_VTX_RIGHT ? topDelta : endDelta; + startEvent = MID_VTX_RIGHT ? startEvent : topEvent; + startDelta = MID_VTX_RIGHT ? startDelta : topDelta; + } + + // Traverse the top half of the triangle + if (tileRowIdx < tileEndRowIdx) + { + int i0 = MID_VTX_RIGHT + 0; + int i1 = MID_VTX_RIGHT + 1; + for (;;) + { + int start = 0, end = bbWidth; + if (TIGHT_TRAVERSAL) + { + // Compute tighter start and endpoints to avoid traversing lots of empty space + start = max(0, min(bbWidth - 1, startEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + end = min(bbWidth, ((int)endEvent >> (TILE_WIDTH_SHIFT + FP_BITS))); + startEvent += startDelta; + endEvent += endDelta; + } + + // Traverse the scanline and update the masked hierarchical z buffer + cullResult = TraverseScanline(start, end, tileRowIdx, MID_VTX_RIGHT + 0, MID_VTX_RIGHT + 1, triEvent, zTriMin, zTriMax, z0, zx); + + if (TEST_Z && cullResult == CullingResult::VISIBLE) // Early out if performing occlusion query + return CullingResult::VISIBLE; + + // move to the next scanline of tiles, update edge events and interpolate z + tileRowIdx += mTilesWidth; + if (tileRowIdx >= tileEndRowIdx) + break; + z0 = _mmw_add_ps(z0, _mmw_set1_ps(zy)); + UPDATE_TILE_EVENTS_Y(i0); + UPDATE_TILE_EVENTS_Y(i1); + } + } + } + + return TEST_Z ? CullingResult::OCCLUDED : CullingResult::VISIBLE; + } + + template +#if PRECISE_COVERAGE != 0 + FORCE_INLINE int RasterizeTriangleBatch(__mwi ipVtxX[3], __mwi ipVtxY[3], __mw pVtxX[3], __mw pVtxY[3], __mw pVtxZ[3], unsigned int triMask, const ScissorRect *scissor) +#else + FORCE_INLINE int RasterizeTriangleBatch(__mw pVtxX[3], __mw pVtxY[3], __mw pVtxZ[3], unsigned int triMask, const ScissorRect *scissor) +#endif + { + int cullResult = CullingResult::VIEW_CULLED; + + ////////////////////////////////////////////////////////////////////////////// + // Compute bounding box and clamp to tile coordinates + ////////////////////////////////////////////////////////////////////////////// + + __mwi bbPixelMinX, bbPixelMinY, bbPixelMaxX, bbPixelMaxY; + ComputeBoundingBox(bbPixelMinX, bbPixelMinY, bbPixelMaxX, bbPixelMaxY, pVtxX, pVtxY, scissor); + + // Clamp bounding box to tiles (it's already padded in computeBoundingBox) + __mwi bbTileMinX = _mmw_srai_epi32(bbPixelMinX, TILE_WIDTH_SHIFT); + __mwi bbTileMinY = _mmw_srai_epi32(bbPixelMinY, TILE_HEIGHT_SHIFT); + __mwi bbTileMaxX = _mmw_srai_epi32(bbPixelMaxX, TILE_WIDTH_SHIFT); + __mwi bbTileMaxY = _mmw_srai_epi32(bbPixelMaxY, TILE_HEIGHT_SHIFT); + __mwi bbTileSizeX = _mmw_sub_epi32(bbTileMaxX, bbTileMinX); + __mwi bbTileSizeY = _mmw_sub_epi32(bbTileMaxY, bbTileMinY); + + // Cull triangles with zero bounding box + __mwi bboxSign = _mmw_or_epi32(_mmw_sub_epi32(bbTileSizeX, _mmw_set1_epi32(1)), _mmw_sub_epi32(bbTileSizeY, _mmw_set1_epi32(1))); + triMask &= ~_mmw_movemask_ps(simd_cast<__mw>(bboxSign)) & SIMD_ALL_LANES_MASK; + if (triMask == 0x0) + return cullResult; + + if (!TEST_Z) + cullResult = CullingResult::VISIBLE; + + ////////////////////////////////////////////////////////////////////////////// + // Set up screen space depth plane + ////////////////////////////////////////////////////////////////////////////// + + __mw zPixelDx, zPixelDy; + ComputeDepthPlane(pVtxX, pVtxY, pVtxZ, zPixelDx, zPixelDy); + + // Compute z value at min corner of bounding box. Offset to make sure z is conservative for all 8x4 subtiles + __mw bbMinXV0 = _mmw_sub_ps(_mmw_cvtepi32_ps(bbPixelMinX), pVtxX[0]); + __mw bbMinYV0 = _mmw_sub_ps(_mmw_cvtepi32_ps(bbPixelMinY), pVtxY[0]); + __mw zPlaneOffset = _mmw_fmadd_ps(zPixelDx, bbMinXV0, _mmw_fmadd_ps(zPixelDy, bbMinYV0, pVtxZ[0])); + __mw zTileDx = _mmw_mul_ps(zPixelDx, _mmw_set1_ps((float)TILE_WIDTH)); + __mw zTileDy = _mmw_mul_ps(zPixelDy, _mmw_set1_ps((float)TILE_HEIGHT)); + if (TEST_Z) + { + zPlaneOffset = _mmw_add_ps(zPlaneOffset, _mmw_max_ps(_mmw_setzero_ps(), _mmw_mul_ps(zPixelDx, _mmw_set1_ps(SUB_TILE_WIDTH)))); + zPlaneOffset = _mmw_add_ps(zPlaneOffset, _mmw_max_ps(_mmw_setzero_ps(), _mmw_mul_ps(zPixelDy, _mmw_set1_ps(SUB_TILE_HEIGHT)))); + } + else + { + zPlaneOffset = _mmw_add_ps(zPlaneOffset, _mmw_min_ps(_mmw_setzero_ps(), _mmw_mul_ps(zPixelDx, _mmw_set1_ps(SUB_TILE_WIDTH)))); + zPlaneOffset = _mmw_add_ps(zPlaneOffset, _mmw_min_ps(_mmw_setzero_ps(), _mmw_mul_ps(zPixelDy, _mmw_set1_ps(SUB_TILE_HEIGHT)))); + } + + // Compute Zmin and Zmax for the triangle (used to narrow the range for difficult tiles) + __mw zMin = _mmw_min_ps(pVtxZ[0], _mmw_min_ps(pVtxZ[1], pVtxZ[2])); + __mw zMax = _mmw_max_ps(pVtxZ[0], _mmw_max_ps(pVtxZ[1], pVtxZ[2])); + + ////////////////////////////////////////////////////////////////////////////// + // Sort vertices (v0 has lowest Y, and the rest is in winding order) and + // compute edges. Also find the middle vertex and compute tile + ////////////////////////////////////////////////////////////////////////////// + +#if PRECISE_COVERAGE != 0 + + // Rotate the triangle in the winding order until v0 is the vertex with lowest Y value + SortVertices(ipVtxX, ipVtxY); + + // Compute edges + __mwi edgeX[3] = { _mmw_sub_epi32(ipVtxX[1], ipVtxX[0]), _mmw_sub_epi32(ipVtxX[2], ipVtxX[1]), _mmw_sub_epi32(ipVtxX[2], ipVtxX[0]) }; + __mwi edgeY[3] = { _mmw_sub_epi32(ipVtxY[1], ipVtxY[0]), _mmw_sub_epi32(ipVtxY[2], ipVtxY[1]), _mmw_sub_epi32(ipVtxY[2], ipVtxY[0]) }; + + // Classify if the middle vertex is on the left or right and compute its position + int midVtxRight = ~_mmw_movemask_ps(simd_cast<__mw>(edgeY[1])); + __mwi midPixelX = _mmw_blendv_epi32(ipVtxX[1], ipVtxX[2], edgeY[1]); + __mwi midPixelY = _mmw_blendv_epi32(ipVtxY[1], ipVtxY[2], edgeY[1]); + __mwi midTileY = _mmw_srai_epi32(_mmw_max_epi32(midPixelY, SIMD_BITS_ZERO), TILE_HEIGHT_SHIFT + FP_BITS); + __mwi bbMidTileY = _mmw_max_epi32(bbTileMinY, _mmw_min_epi32(bbTileMaxY, midTileY)); + + // Compute edge events for the bottom of the bounding box, or for the middle tile in case of + // the edge originating from the middle vertex. + __mwi xDiffi[2], yDiffi[2]; + xDiffi[0] = _mmw_sub_epi32(ipVtxX[0], _mmw_slli_epi32(bbPixelMinX, FP_BITS)); + xDiffi[1] = _mmw_sub_epi32(midPixelX, _mmw_slli_epi32(bbPixelMinX, FP_BITS)); + yDiffi[0] = _mmw_sub_epi32(ipVtxY[0], _mmw_slli_epi32(bbPixelMinY, FP_BITS)); + yDiffi[1] = _mmw_sub_epi32(midPixelY, _mmw_slli_epi32(bbMidTileY, FP_BITS + TILE_HEIGHT_SHIFT)); + + ////////////////////////////////////////////////////////////////////////////// + // Edge slope setup - Note we do not conform to DX/GL rasterization rules + ////////////////////////////////////////////////////////////////////////////// + + // Potentially flip edge to ensure that all edges have positive Y slope. + edgeX[1] = _mmw_blendv_epi32(edgeX[1], _mmw_neg_epi32(edgeX[1]), edgeY[1]); + edgeY[1] = _mmw_abs_epi32(edgeY[1]); + + // Compute floating point slopes + __mw slope[3]; + slope[0] = _mmw_div_ps(_mmw_cvtepi32_ps(edgeX[0]), _mmw_cvtepi32_ps(edgeY[0])); + slope[1] = _mmw_div_ps(_mmw_cvtepi32_ps(edgeX[1]), _mmw_cvtepi32_ps(edgeY[1])); + slope[2] = _mmw_div_ps(_mmw_cvtepi32_ps(edgeX[2]), _mmw_cvtepi32_ps(edgeY[2])); + + // Modify slope of horizontal edges to make sure they mask out pixels above/below the edge. The slope is set to screen + // width to mask out all pixels above or below the horizontal edge. We must also add a small bias to acount for that + // vertices may end up off screen due to clipping. We're assuming that the round off error is no bigger than 1.0 + __mw horizontalSlopeDelta = _mmw_set1_ps(2.0f * ((float)mWidth + 2.0f*(GUARD_BAND_PIXEL_SIZE + 1.0f))); + __mwi horizontalSlope0 = _mmw_cmpeq_epi32(edgeY[0], _mmw_setzero_epi32()); + __mwi horizontalSlope1 = _mmw_cmpeq_epi32(edgeY[1], _mmw_setzero_epi32()); + slope[0] = _mmw_blendv_ps(slope[0], horizontalSlopeDelta, simd_cast<__mw>(horizontalSlope0)); + slope[1] = _mmw_blendv_ps(slope[1], _mmw_neg_ps(horizontalSlopeDelta), simd_cast<__mw>(horizontalSlope1)); + + __mwi vy[3] = { yDiffi[0], yDiffi[1], yDiffi[0] }; + __mwi offset0 = _mmw_and_epi32(_mmw_add_epi32(yDiffi[0], _mmw_set1_epi32(FP_HALF_PIXEL - 1)), _mmw_set1_epi32((int)((~0u) << FP_BITS))); + __mwi offset1 = _mmw_and_epi32(_mmw_add_epi32(yDiffi[1], _mmw_set1_epi32(FP_HALF_PIXEL - 1)), _mmw_set1_epi32((int)((~0u) << FP_BITS))); + vy[0] = _mmw_blendv_epi32(yDiffi[0], offset0, horizontalSlope0); + vy[1] = _mmw_blendv_epi32(yDiffi[1], offset1, horizontalSlope1); + + // Compute edge events for the bottom of the bounding box, or for the middle tile in case of + // the edge originating from the middle vertex. + __mwi slopeSign[3], absEdgeX[3]; + __mwi slopeTileDelta[3], eventStartRemainder[3], slopeTileRemainder[3], eventStart[3]; + for (int i = 0; i < 3; i++) + { + // Common, compute slope sign (used to propagate the remainder term when overflowing) is postive or negative x-direction + slopeSign[i] = _mmw_blendv_epi32(_mmw_set1_epi32(1), _mmw_set1_epi32(-1), edgeX[i]); + absEdgeX[i] = _mmw_abs_epi32(edgeX[i]); + + // Delta and error term for one vertical tile step. The exact delta is exactDelta = edgeX / edgeY, due to limited precision we + // repersent the delta as delta = qoutient + remainder / edgeY, where quotient = int(edgeX / edgeY). In this case, since we step + // one tile of scanlines at a time, the slope is computed for a tile-sized step. + slopeTileDelta[i] = _mmw_cvttps_epi32(_mmw_mul_ps(slope[i], _mmw_set1_ps(FP_TILE_HEIGHT))); + slopeTileRemainder[i] = _mmw_sub_epi32(_mmw_slli_epi32(absEdgeX[i], FP_TILE_HEIGHT_SHIFT), _mmw_mullo_epi32(_mmw_abs_epi32(slopeTileDelta[i]), edgeY[i])); + + // Jump to bottom scanline of tile row, this is the bottom of the bounding box, or the middle vertex of the triangle. + // The jump can be in both positive and negative y-direction due to clipping / offscreen vertices. + __mwi tileStartDir = _mmw_blendv_epi32(slopeSign[i], _mmw_neg_epi32(slopeSign[i]), vy[i]); + __mwi tieBreaker = _mmw_blendv_epi32(_mmw_set1_epi32(0), _mmw_set1_epi32(1), tileStartDir); + __mwi tileStartSlope = _mmw_cvttps_epi32(_mmw_mul_ps(slope[i], _mmw_cvtepi32_ps(_mmw_neg_epi32(vy[i])))); + __mwi tileStartRemainder = _mmw_sub_epi32(_mmw_mullo_epi32(absEdgeX[i], _mmw_abs_epi32(vy[i])), _mmw_mullo_epi32(_mmw_abs_epi32(tileStartSlope), edgeY[i])); + + eventStartRemainder[i] = _mmw_sub_epi32(tileStartRemainder, tieBreaker); + __mwi overflow = _mmw_srai_epi32(eventStartRemainder[i], 31); + eventStartRemainder[i] = _mmw_add_epi32(eventStartRemainder[i], _mmw_and_epi32(overflow, edgeY[i])); + eventStartRemainder[i] = _mmw_blendv_epi32(eventStartRemainder[i], _mmw_sub_epi32(_mmw_sub_epi32(edgeY[i], eventStartRemainder[i]), _mmw_set1_epi32(1)), vy[i]); + + //eventStart[i] = xDiffi[i & 1] + tileStartSlope + (overflow & tileStartDir) + _mmw_set1_epi32(FP_HALF_PIXEL - 1) + tieBreaker; + eventStart[i] = _mmw_add_epi32(_mmw_add_epi32(xDiffi[i & 1], tileStartSlope), _mmw_and_epi32(overflow, tileStartDir)); + eventStart[i] = _mmw_add_epi32(_mmw_add_epi32(eventStart[i], _mmw_set1_epi32(FP_HALF_PIXEL - 1)), tieBreaker); + } + +#else // PRECISE_COVERAGE + + SortVertices(pVtxX, pVtxY); + + // Compute edges + __mw edgeX[3] = { _mmw_sub_ps(pVtxX[1], pVtxX[0]), _mmw_sub_ps(pVtxX[2], pVtxX[1]), _mmw_sub_ps(pVtxX[2], pVtxX[0]) }; + __mw edgeY[3] = { _mmw_sub_ps(pVtxY[1], pVtxY[0]), _mmw_sub_ps(pVtxY[2], pVtxY[1]), _mmw_sub_ps(pVtxY[2], pVtxY[0]) }; + + // Classify if the middle vertex is on the left or right and compute its position + int midVtxRight = ~_mmw_movemask_ps(edgeY[1]); + __mw midPixelX = _mmw_blendv_ps(pVtxX[1], pVtxX[2], edgeY[1]); + __mw midPixelY = _mmw_blendv_ps(pVtxY[1], pVtxY[2], edgeY[1]); + __mwi midTileY = _mmw_srai_epi32(_mmw_max_epi32(_mmw_cvttps_epi32(midPixelY), SIMD_BITS_ZERO), TILE_HEIGHT_SHIFT); + __mwi bbMidTileY = _mmw_max_epi32(bbTileMinY, _mmw_min_epi32(bbTileMaxY, midTileY)); + + ////////////////////////////////////////////////////////////////////////////// + // Edge slope setup - Note we do not conform to DX/GL rasterization rules + ////////////////////////////////////////////////////////////////////////////// + + // Compute floating point slopes + __mw slope[3]; + slope[0] = _mmw_div_ps(edgeX[0], edgeY[0]); + slope[1] = _mmw_div_ps(edgeX[1], edgeY[1]); + slope[2] = _mmw_div_ps(edgeX[2], edgeY[2]); + + // Modify slope of horizontal edges to make sure they mask out pixels above/below the edge. The slope is set to screen + // width to mask out all pixels above or below the horizontal edge. We must also add a small bias to acount for that + // vertices may end up off screen due to clipping. We're assuming that the round off error is no bigger than 1.0 + __mw horizontalSlopeDelta = _mmw_set1_ps((float)mWidth + 2.0f*(GUARD_BAND_PIXEL_SIZE + 1.0f)); + slope[0] = _mmw_blendv_ps(slope[0], horizontalSlopeDelta, _mmw_cmpeq_ps(edgeY[0], _mmw_setzero_ps())); + slope[1] = _mmw_blendv_ps(slope[1], _mmw_neg_ps(horizontalSlopeDelta), _mmw_cmpeq_ps(edgeY[1], _mmw_setzero_ps())); + + // Convert floaing point slopes to fixed point + __mwi slopeFP[3]; + slopeFP[0] = _mmw_cvttps_epi32(_mmw_mul_ps(slope[0], _mmw_set1_ps(1 << FP_BITS))); + slopeFP[1] = _mmw_cvttps_epi32(_mmw_mul_ps(slope[1], _mmw_set1_ps(1 << FP_BITS))); + slopeFP[2] = _mmw_cvttps_epi32(_mmw_mul_ps(slope[2], _mmw_set1_ps(1 << FP_BITS))); + + // Fan out edge slopes to avoid (rare) cracks at vertices. We increase right facing slopes + // by 1 LSB, which results in overshooting vertices slightly, increasing triangle coverage. + // e0 is always right facing, e1 depends on if the middle vertex is on the left or right + slopeFP[0] = _mmw_add_epi32(slopeFP[0], _mmw_set1_epi32(1)); + slopeFP[1] = _mmw_add_epi32(slopeFP[1], _mmw_srli_epi32(_mmw_not_epi32(simd_cast<__mwi>(edgeY[1])), 31)); + + // Compute slope deltas for an SIMD_LANES scanline step (tile height) + __mwi slopeTileDelta[3]; + slopeTileDelta[0] = _mmw_slli_epi32(slopeFP[0], TILE_HEIGHT_SHIFT); + slopeTileDelta[1] = _mmw_slli_epi32(slopeFP[1], TILE_HEIGHT_SHIFT); + slopeTileDelta[2] = _mmw_slli_epi32(slopeFP[2], TILE_HEIGHT_SHIFT); + + // Compute edge events for the bottom of the bounding box, or for the middle tile in case of + // the edge originating from the middle vertex. + __mwi xDiffi[2], yDiffi[2]; + xDiffi[0] = _mmw_slli_epi32(_mmw_sub_epi32(_mmw_cvttps_epi32(pVtxX[0]), bbPixelMinX), FP_BITS); + xDiffi[1] = _mmw_slli_epi32(_mmw_sub_epi32(_mmw_cvttps_epi32(midPixelX), bbPixelMinX), FP_BITS); + yDiffi[0] = _mmw_sub_epi32(_mmw_cvttps_epi32(pVtxY[0]), bbPixelMinY); + yDiffi[1] = _mmw_sub_epi32(_mmw_cvttps_epi32(midPixelY), _mmw_slli_epi32(bbMidTileY, TILE_HEIGHT_SHIFT)); + + __mwi eventStart[3]; + eventStart[0] = _mmw_sub_epi32(xDiffi[0], _mmw_mullo_epi32(slopeFP[0], yDiffi[0])); + eventStart[1] = _mmw_sub_epi32(xDiffi[1], _mmw_mullo_epi32(slopeFP[1], yDiffi[1])); + eventStart[2] = _mmw_sub_epi32(xDiffi[0], _mmw_mullo_epi32(slopeFP[2], yDiffi[0])); +#endif + + ////////////////////////////////////////////////////////////////////////////// + // Split bounding box into bottom - middle - top region. + ////////////////////////////////////////////////////////////////////////////// + + __mwi bbBottomIdx = _mmw_add_epi32(bbTileMinX, _mmw_mullo_epi32(bbTileMinY, _mmw_set1_epi32(mTilesWidth))); + __mwi bbTopIdx = _mmw_add_epi32(bbTileMinX, _mmw_mullo_epi32(_mmw_add_epi32(bbTileMinY, bbTileSizeY), _mmw_set1_epi32(mTilesWidth))); + __mwi bbMidIdx = _mmw_add_epi32(bbTileMinX, _mmw_mullo_epi32(midTileY, _mmw_set1_epi32(mTilesWidth))); + + ////////////////////////////////////////////////////////////////////////////// + // Loop over non-culled triangle and change SIMD axis to per-pixel + ////////////////////////////////////////////////////////////////////////////// + while (triMask) + { + unsigned int triIdx = find_clear_lsb(&triMask); + int triMidVtxRight = (midVtxRight >> triIdx) & 1; + + // Get Triangle Zmin zMax + __mw zTriMax = _mmw_set1_ps(simd_f32(zMax)[triIdx]); + __mw zTriMin = _mmw_set1_ps(simd_f32(zMin)[triIdx]); + + // Setup Zmin value for first set of 8x4 subtiles + __mw z0 = _mmw_fmadd_ps(_mmw_set1_ps(simd_f32(zPixelDx)[triIdx]), SIMD_SUB_TILE_COL_OFFSET_F, + _mmw_fmadd_ps(_mmw_set1_ps(simd_f32(zPixelDy)[triIdx]), SIMD_SUB_TILE_ROW_OFFSET_F, _mmw_set1_ps(simd_f32(zPlaneOffset)[triIdx]))); + float zx = simd_f32(zTileDx)[triIdx]; + float zy = simd_f32(zTileDy)[triIdx]; + + // Get dimension of bounding box bottom, mid & top segments + int bbWidth = simd_i32(bbTileSizeX)[triIdx]; + int bbHeight = simd_i32(bbTileSizeY)[triIdx]; + int tileRowIdx = simd_i32(bbBottomIdx)[triIdx]; + int tileMidRowIdx = simd_i32(bbMidIdx)[triIdx]; + int tileEndRowIdx = simd_i32(bbTopIdx)[triIdx]; + + if (bbWidth > BIG_TRIANGLE && bbHeight > BIG_TRIANGLE) // For big triangles we use a more expensive but tighter traversal algorithm + { +#if PRECISE_COVERAGE != 0 + if (triMidVtxRight) + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slope, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy, edgeY, absEdgeX, slopeSign, eventStartRemainder, slopeTileRemainder); + else + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slope, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy, edgeY, absEdgeX, slopeSign, eventStartRemainder, slopeTileRemainder); +#else + if (triMidVtxRight) + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slopeFP, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy); + else + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slopeFP, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy); +#endif + } + else + { +#if PRECISE_COVERAGE != 0 + if (triMidVtxRight) + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slope, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy, edgeY, absEdgeX, slopeSign, eventStartRemainder, slopeTileRemainder); + else + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slope, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy, edgeY, absEdgeX, slopeSign, eventStartRemainder, slopeTileRemainder); +#else + if (triMidVtxRight) + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slopeFP, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy); + else + cullResult &= RasterizeTriangle(triIdx, bbWidth, tileRowIdx, tileMidRowIdx, tileEndRowIdx, eventStart, slopeFP, slopeTileDelta, zTriMin, zTriMax, z0, zx, zy); +#endif + } + + if (TEST_Z && cullResult == CullingResult::VISIBLE) + return CullingResult::VISIBLE; + } + + return cullResult; + } + + template + FORCE_INLINE CullingResult RenderTriangles(const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix, BackfaceWinding bfWinding, ClipPlanes clipPlaneMask, const VertexLayout &vtxLayout) + { + assert(mMaskedHiZBuffer != nullptr); + + if (TEST_Z) + STATS_ADD(mStats.mOccludees.mNumProcessedTriangles, nTris); + else + STATS_ADD(mStats.mOccluders.mNumProcessedTriangles, nTris); + +#if PRECISE_COVERAGE != 0 + int originalRoundingMode = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); +#endif + + int clipHead = 0; + int clipTail = 0; + __m128 clipTriBuffer[MAX_CLIPPED * 3]; + int cullResult = CullingResult::VIEW_CULLED; + + const unsigned int *inTrisPtr = inTris; + int numLanes = SIMD_LANES; + int triIndex = 0; + while (triIndex < nTris || clipHead != clipTail) + { + __mw vtxX[3], vtxY[3], vtxW[3]; + unsigned int triMask = SIMD_ALL_LANES_MASK; + + GatherTransformClip( clipHead, clipTail, numLanes, nTris, triIndex, vtxX, vtxY, vtxW, inVtx, inTrisPtr, vtxLayout, modelToClipMatrix, clipTriBuffer, triMask, clipPlaneMask ); + + if (triMask == 0x0) + continue; + + ////////////////////////////////////////////////////////////////////////////// + // Project, transform to screen space and perform backface culling. Note + // that we use z = 1.0 / vtx.w for depth, which means that z = 0 is far and + // z = 1 is near. We must also use a greater than depth test, and in effect + // everything is reversed compared to regular z implementations. + ////////////////////////////////////////////////////////////////////////////// + + __mw pVtxX[3], pVtxY[3], pVtxZ[3]; + +#if PRECISE_COVERAGE != 0 + __mwi ipVtxX[3], ipVtxY[3]; + ProjectVertices(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, vtxX, vtxY, vtxW); +#else + ProjectVertices(pVtxX, pVtxY, pVtxZ, vtxX, vtxY, vtxW); +#endif + + // Perform backface test. + __mw triArea1 = _mmw_mul_ps(_mmw_sub_ps(pVtxX[1], pVtxX[0]), _mmw_sub_ps(pVtxY[2], pVtxY[0])); + __mw triArea2 = _mmw_mul_ps(_mmw_sub_ps(pVtxX[0], pVtxX[2]), _mmw_sub_ps(pVtxY[0], pVtxY[1])); + __mw triArea = _mmw_sub_ps(triArea1, triArea2); + __mw ccwMask = _mmw_cmpgt_ps(triArea, _mmw_setzero_ps()); + +#if PRECISE_COVERAGE != 0 + triMask &= CullBackfaces(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, ccwMask, bfWinding); +#else + triMask &= CullBackfaces(pVtxX, pVtxY, pVtxZ, ccwMask, bfWinding); +#endif + + if (triMask == 0x0) + continue; + + ////////////////////////////////////////////////////////////////////////////// + // Setup and rasterize a SIMD batch of triangles + ////////////////////////////////////////////////////////////////////////////// +#if PRECISE_COVERAGE != 0 + cullResult &= RasterizeTriangleBatch(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, triMask, &mFullscreenScissor); +#else + cullResult &= RasterizeTriangleBatch(pVtxX, pVtxY, pVtxZ, triMask, &mFullscreenScissor); +#endif + + if (TEST_Z && cullResult == CullingResult::VISIBLE) { +#if PRECISE_COVERAGE != 0 + _MM_SET_ROUNDING_MODE(originalRoundingMode); +#endif + return CullingResult::VISIBLE; + } + } + +#if PRECISE_COVERAGE != 0 + _MM_SET_ROUNDING_MODE(originalRoundingMode); +#endif + return (CullingResult)cullResult; + } + + CullingResult RenderTriangles(const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix, BackfaceWinding bfWinding, ClipPlanes clipPlaneMask, const VertexLayout &vtxLayout) override + { + CullingResult retVal; + + if (vtxLayout.mStride == 16 && vtxLayout.mOffsetY == 4 && vtxLayout.mOffsetW == 12) + retVal = (CullingResult)RenderTriangles<0, 1>(inVtx, inTris, nTris, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + else + retVal = (CullingResult)RenderTriangles<0, 0>(inVtx, inTris, nTris, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + +#if MOC_RECORDER_ENABLE + RecordRenderTriangles( inVtx, inTris, nTris, modelToClipMatrix, clipPlaneMask, bfWinding, vtxLayout, retVal ); +#endif + return retVal; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Occlusion query functions + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + CullingResult TestTriangles(const float *inVtx, const unsigned int *inTris, int nTris, const float *modelToClipMatrix, BackfaceWinding bfWinding, ClipPlanes clipPlaneMask, const VertexLayout &vtxLayout) override + { + CullingResult retVal; + + if (vtxLayout.mStride == 16 && vtxLayout.mOffsetY == 4 && vtxLayout.mOffsetW == 12) + retVal = (CullingResult)RenderTriangles<1, 1>(inVtx, inTris, nTris, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + else + retVal = (CullingResult)RenderTriangles<1, 0>(inVtx, inTris, nTris, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + +#if MOC_RECORDER_ENABLE + { + std::lock_guard lock( mRecorderMutex ); + if( mRecorder != nullptr ) mRecorder->RecordTestTriangles( retVal, inVtx, inTris, nTris, modelToClipMatrix, clipPlaneMask, bfWinding, vtxLayout ); + } +#endif + return retVal; + } + + CullingResult TestRect( float xmin, float ymin, float xmax, float ymax, float wmin ) const override + { + STATS_ADD(mStats.mOccludees.mNumProcessedRectangles, 1); + assert(mMaskedHiZBuffer != nullptr); + + static const __m128i SIMD_TILE_PAD = _mm_setr_epi32(0, TILE_WIDTH, 0, TILE_HEIGHT); + static const __m128i SIMD_TILE_PAD_MASK = _mm_setr_epi32(~(TILE_WIDTH - 1), ~(TILE_WIDTH - 1), ~(TILE_HEIGHT - 1), ~(TILE_HEIGHT - 1)); + static const __m128i SIMD_SUB_TILE_PAD = _mm_setr_epi32(0, SUB_TILE_WIDTH, 0, SUB_TILE_HEIGHT); + static const __m128i SIMD_SUB_TILE_PAD_MASK = _mm_setr_epi32(~(SUB_TILE_WIDTH - 1), ~(SUB_TILE_WIDTH - 1), ~(SUB_TILE_HEIGHT - 1), ~(SUB_TILE_HEIGHT - 1)); + + ////////////////////////////////////////////////////////////////////////////// + // Compute screen space bounding box and guard for out of bounds + ////////////////////////////////////////////////////////////////////////////// +#if USE_D3D != 0 + __m128 pixelBBox = _mmx_fmadd_ps(_mm_setr_ps(xmin, xmax, ymax, ymin), mIHalfSize, mICenter); +#else + __m128 pixelBBox = _mmx_fmadd_ps(_mm_setr_ps(xmin, xmax, ymin, ymax), mIHalfSize, mICenter); +#endif + __m128i pixelBBoxi = _mm_cvttps_epi32(pixelBBox); + pixelBBoxi = _mmx_max_epi32(_mm_setzero_si128(), _mmx_min_epi32(mIScreenSize, pixelBBoxi)); + + ////////////////////////////////////////////////////////////////////////////// + // Pad bounding box to (32xN) tiles. Tile BB is used for looping / traversal + ////////////////////////////////////////////////////////////////////////////// + __m128i tileBBoxi = _mm_and_si128(_mm_add_epi32(pixelBBoxi, SIMD_TILE_PAD), SIMD_TILE_PAD_MASK); + int txMin = simd_i32(tileBBoxi)[0] >> TILE_WIDTH_SHIFT; + int txMax = simd_i32(tileBBoxi)[1] >> TILE_WIDTH_SHIFT; + int tileRowIdx = (simd_i32(tileBBoxi)[2] >> TILE_HEIGHT_SHIFT)*mTilesWidth; + int tileRowIdxEnd = (simd_i32(tileBBoxi)[3] >> TILE_HEIGHT_SHIFT)*mTilesWidth; + + if (simd_i32(tileBBoxi)[0] == simd_i32(tileBBoxi)[1] || simd_i32(tileBBoxi)[2] == simd_i32(tileBBoxi)[3]) + { +#if MOC_RECORDER_ENABLE + { + std::lock_guard lock( mRecorderMutex ); + if( mRecorder != nullptr ) mRecorder->RecordTestRect( CullingResult::VIEW_CULLED, xmin, ymin, xmax, ymax, wmin ); + } +#endif + return CullingResult::VIEW_CULLED; + } + + /////////////////////////////////////////////////////////////////////////////// + // Pad bounding box to (8x4) subtiles. Skip SIMD lanes outside the subtile BB + /////////////////////////////////////////////////////////////////////////////// + __m128i subTileBBoxi = _mm_and_si128(_mm_add_epi32(pixelBBoxi, SIMD_SUB_TILE_PAD), SIMD_SUB_TILE_PAD_MASK); + __mwi stxmin = _mmw_set1_epi32(simd_i32(subTileBBoxi)[0] - 1); // - 1 to be able to use GT test + __mwi stymin = _mmw_set1_epi32(simd_i32(subTileBBoxi)[2] - 1); // - 1 to be able to use GT test + __mwi stxmax = _mmw_set1_epi32(simd_i32(subTileBBoxi)[1]); + __mwi stymax = _mmw_set1_epi32(simd_i32(subTileBBoxi)[3]); + + // Setup pixel coordinates used to discard lanes outside subtile BB + __mwi startPixelX = _mmw_add_epi32(SIMD_SUB_TILE_COL_OFFSET, _mmw_set1_epi32(simd_i32(tileBBoxi)[0])); + __mwi pixelY = _mmw_add_epi32(SIMD_SUB_TILE_ROW_OFFSET, _mmw_set1_epi32(simd_i32(tileBBoxi)[2])); + + ////////////////////////////////////////////////////////////////////////////// + // Compute z from w. Note that z is reversed order, 0 = far, 1 = near, which + // means we use a greater than test, so zMax is used to test for visibility. + ////////////////////////////////////////////////////////////////////////////// + __mw zMax = _mmw_div_ps(_mmw_set1_ps(1.0f), _mmw_set1_ps(wmin)); + + for (;;) + { + __mwi pixelX = startPixelX; + for (int tx = txMin;;) + { + STATS_ADD(mStats.mOccludees.mNumTilesTraversed, 1); + + int tileIdx = tileRowIdx + tx; + assert(tileIdx >= 0 && tileIdx < mTilesWidth*mTilesHeight); + + // Fetch zMin from masked hierarchical Z buffer +#if QUICK_MASK != 0 + __mw zBuf = mMaskedHiZBuffer[tileIdx].mZMin[0]; +#else + __mwi mask = mMaskedHiZBuffer[tileIdx].mMask; + __mw zMin0 = _mmw_blendv_ps(mMaskedHiZBuffer[tileIdx].mZMin[0], mMaskedHiZBuffer[tileIdx].mZMin[1], simd_cast<__mw>(_mmw_cmpeq_epi32(mask, _mmw_set1_epi32(~0)))); + __mw zMin1 = _mmw_blendv_ps(mMaskedHiZBuffer[tileIdx].mZMin[1], mMaskedHiZBuffer[tileIdx].mZMin[0], simd_cast<__mw>(_mmw_cmpeq_epi32(mask, _mmw_setzero_epi32()))); + __mw zBuf = _mmw_min_ps(zMin0, zMin1); +#endif + // Perform conservative greater than test against hierarchical Z buffer (zMax >= zBuf means the subtile is visible) + __mwi zPass = simd_cast<__mwi>(_mmw_cmpge_ps(zMax, zBuf)); //zPass = zMax >= zBuf ? ~0 : 0 + + // Mask out lanes corresponding to subtiles outside the bounding box + __mwi bboxTestMin = _mmw_and_epi32(_mmw_cmpgt_epi32(pixelX, stxmin), _mmw_cmpgt_epi32(pixelY, stymin)); + __mwi bboxTestMax = _mmw_and_epi32(_mmw_cmpgt_epi32(stxmax, pixelX), _mmw_cmpgt_epi32(stymax, pixelY)); + __mwi boxMask = _mmw_and_epi32(bboxTestMin, bboxTestMax); + zPass = _mmw_and_epi32(zPass, boxMask); + + // If not all tiles failed the conservative z test we can immediately terminate the test + if (!_mmw_testz_epi32(zPass, zPass)) + { +#if MOC_RECORDER_ENABLE + { + std::lock_guard lock( mRecorderMutex ); + if( mRecorder != nullptr ) mRecorder->RecordTestRect( CullingResult::VISIBLE, xmin, ymin, xmax, ymax, wmin ); + } +#endif + return CullingResult::VISIBLE; + } + + if (++tx >= txMax) + break; + pixelX = _mmw_add_epi32(pixelX, _mmw_set1_epi32(TILE_WIDTH)); + } + + tileRowIdx += mTilesWidth; + if (tileRowIdx >= tileRowIdxEnd) + break; + pixelY = _mmw_add_epi32(pixelY, _mmw_set1_epi32(TILE_HEIGHT)); + } +#if MOC_RECORDER_ENABLE + { + std::lock_guard lock( mRecorderMutex ); + if( mRecorder != nullptr ) mRecorder->RecordTestRect( CullingResult::OCCLUDED, xmin, ymin, xmax, ymax, wmin ); + } +#endif + return CullingResult::OCCLUDED; + } + + template + FORCE_INLINE void BinTriangles(const float *inVtx, const unsigned int *inTris, int nTris, TriList *triLists, unsigned int nBinsW, unsigned int nBinsH, const float *modelToClipMatrix, BackfaceWinding bfWinding, ClipPlanes clipPlaneMask, const VertexLayout &vtxLayout) + { + assert(mMaskedHiZBuffer != nullptr); + +#if PRECISE_COVERAGE != 0 + int originalRoundingMode = _MM_GET_ROUNDING_MODE(); + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); +#endif + + STATS_ADD(mStats.mOccluders.mNumProcessedTriangles, nTris); + + int clipHead = 0; + int clipTail = 0; + __m128 clipTriBuffer[MAX_CLIPPED * 3]; + + const unsigned int *inTrisPtr = inTris; + int numLanes = SIMD_LANES; + int triIndex = 0; + while (triIndex < nTris || clipHead != clipTail) + { + unsigned int triMask = SIMD_ALL_LANES_MASK; + __mw vtxX[3], vtxY[3], vtxW[3]; + + GatherTransformClip( clipHead, clipTail, numLanes, nTris, triIndex, vtxX, vtxY, vtxW, inVtx, inTrisPtr, vtxLayout, modelToClipMatrix, clipTriBuffer, triMask, clipPlaneMask ); + + if (triMask == 0x0) + continue; + + ////////////////////////////////////////////////////////////////////////////// + // Project, transform to screen space and perform backface culling. Note + // that we use z = 1.0 / vtx.w for depth, which means that z = 0 is far and + // z = 1 is near. We must also use a greater than depth test, and in effect + // everything is reversed compared to regular z implementations. + ////////////////////////////////////////////////////////////////////////////// + + __mw pVtxX[3], pVtxY[3], pVtxZ[3]; + +#if PRECISE_COVERAGE != 0 + __mwi ipVtxX[3], ipVtxY[3]; + ProjectVertices(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, vtxX, vtxY, vtxW); +#else + ProjectVertices(pVtxX, pVtxY, pVtxZ, vtxX, vtxY, vtxW); +#endif + + // Perform backface test. + __mw triArea1 = _mmw_mul_ps(_mmw_sub_ps(pVtxX[1], pVtxX[0]), _mmw_sub_ps(pVtxY[2], pVtxY[0])); + __mw triArea2 = _mmw_mul_ps(_mmw_sub_ps(pVtxX[0], pVtxX[2]), _mmw_sub_ps(pVtxY[0], pVtxY[1])); + __mw triArea = _mmw_sub_ps(triArea1, triArea2); + __mw ccwMask = _mmw_cmpgt_ps(triArea, _mmw_setzero_ps()); + +#if PRECISE_COVERAGE != 0 + triMask &= CullBackfaces(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, ccwMask, bfWinding); +#else + triMask &= CullBackfaces(pVtxX, pVtxY, pVtxZ, ccwMask, bfWinding); +#endif + + if (triMask == 0x0) + continue; + + ////////////////////////////////////////////////////////////////////////////// + // Bin triangles + ////////////////////////////////////////////////////////////////////////////// + + unsigned int binWidth; + unsigned int binHeight; + ComputeBinWidthHeight(nBinsW, nBinsH, binWidth, binHeight); + + // Compute pixel bounding box + __mwi bbPixelMinX, bbPixelMinY, bbPixelMaxX, bbPixelMaxY; + ComputeBoundingBox(bbPixelMinX, bbPixelMinY, bbPixelMaxX, bbPixelMaxY, pVtxX, pVtxY, &mFullscreenScissor); + + while (triMask) + { + unsigned int triIdx = find_clear_lsb(&triMask); + + // Clamp bounding box to bins + int startX = min(nBinsW-1, simd_i32(bbPixelMinX)[triIdx] / binWidth); + int startY = min(nBinsH-1, simd_i32(bbPixelMinY)[triIdx] / binHeight); + int endX = min(nBinsW, (simd_i32(bbPixelMaxX)[triIdx] + binWidth - 1) / binWidth); + int endY = min(nBinsH, (simd_i32(bbPixelMaxY)[triIdx] + binHeight - 1) / binHeight); + + for (int y = startY; y < endY; ++y) + { + for (int x = startX; x < endX; ++x) + { + int binIdx = x + y * nBinsW; + unsigned int writeTriIdx = triLists[binIdx].mTriIdx; + for (int i = 0; i < 3; ++i) + { +#if PRECISE_COVERAGE != 0 + ((int*)triLists[binIdx].mPtr)[i * 3 + writeTriIdx * 9 + 0] = simd_i32(ipVtxX[i])[triIdx]; + ((int*)triLists[binIdx].mPtr)[i * 3 + writeTriIdx * 9 + 1] = simd_i32(ipVtxY[i])[triIdx]; +#else + triLists[binIdx].mPtr[i * 3 + writeTriIdx * 9 + 0] = simd_f32(pVtxX[i])[triIdx]; + triLists[binIdx].mPtr[i * 3 + writeTriIdx * 9 + 1] = simd_f32(pVtxY[i])[triIdx]; +#endif + triLists[binIdx].mPtr[i * 3 + writeTriIdx * 9 + 2] = simd_f32(pVtxZ[i])[triIdx]; + } + triLists[binIdx].mTriIdx++; + } + } + } + } +#if PRECISE_COVERAGE != 0 + _MM_SET_ROUNDING_MODE(originalRoundingMode); +#endif + } + + void BinTriangles(const float *inVtx, const unsigned int *inTris, int nTris, TriList *triLists, unsigned int nBinsW, unsigned int nBinsH, const float *modelToClipMatrix, BackfaceWinding bfWinding, ClipPlanes clipPlaneMask, const VertexLayout &vtxLayout) override + { + if (vtxLayout.mStride == 16 && vtxLayout.mOffsetY == 4 && vtxLayout.mOffsetW == 12) + BinTriangles(inVtx, inTris, nTris, triLists, nBinsW, nBinsH, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + else + BinTriangles(inVtx, inTris, nTris, triLists, nBinsW, nBinsH, modelToClipMatrix, bfWinding, clipPlaneMask, vtxLayout); + } + + template + void GatherTransformClip( int & clipHead, int & clipTail, int & numLanes, int nTris, int & triIndex, __mw * vtxX, __mw * vtxY, __mw * vtxW, const float * inVtx, const unsigned int * &inTrisPtr, const VertexLayout & vtxLayout, const float * modelToClipMatrix, __m128 * clipTriBuffer, unsigned int &triMask, ClipPlanes clipPlaneMask ) + { + ////////////////////////////////////////////////////////////////////////////// + // Assemble triangles from the index list + ////////////////////////////////////////////////////////////////////////////// + unsigned int triClipMask = SIMD_ALL_LANES_MASK; + + if( clipHead != clipTail ) + { + int clippedTris = clipHead > clipTail ? clipHead - clipTail : MAX_CLIPPED + clipHead - clipTail; + clippedTris = min( clippedTris, SIMD_LANES ); + +#if CLIPPING_PRESERVES_ORDER != 0 + // if preserving order, don't mix clipped and new triangles, handle the clip buffer fully + // and then continue gathering; this is not as efficient - ideally we want to gather + // at the end (if clip buffer has less than SIMD_LANES triangles) but that requires + // more modifications below - something to do in the future. + numLanes = 0; +#else + // Fill out SIMD registers by fetching more triangles. + numLanes = max( 0, min( SIMD_LANES - clippedTris, nTris - triIndex ) ); +#endif + + if( numLanes > 0 ) { + if( FAST_GATHER ) + GatherVerticesFast( vtxX, vtxY, vtxW, inVtx, inTrisPtr, numLanes ); + else + GatherVertices( vtxX, vtxY, vtxW, inVtx, inTrisPtr, numLanes, vtxLayout ); + + TransformVerts( vtxX, vtxY, vtxW, modelToClipMatrix ); + } + + for( int clipTri = numLanes; clipTri < numLanes + clippedTris; clipTri++ ) + { + int triIdx = clipTail * 3; + for( int i = 0; i < 3; i++ ) + { + simd_f32( vtxX[i] )[clipTri] = simd_f32( clipTriBuffer[triIdx + i] )[0]; + simd_f32( vtxY[i] )[clipTri] = simd_f32( clipTriBuffer[triIdx + i] )[1]; + simd_f32( vtxW[i] )[clipTri] = simd_f32( clipTriBuffer[triIdx + i] )[2]; + } + clipTail = ( clipTail + 1 ) & ( MAX_CLIPPED - 1 ); + } + + triIndex += numLanes; + inTrisPtr += numLanes * 3; + + triMask = ( 1U << ( clippedTris + numLanes ) ) - 1; + triClipMask = ( 1U << numLanes ) - 1; // Don't re-clip already clipped triangles + } + else + { + numLanes = min( SIMD_LANES, nTris - triIndex ); + triMask = ( 1U << numLanes ) - 1; + triClipMask = triMask; + + if( FAST_GATHER ) + GatherVerticesFast( vtxX, vtxY, vtxW, inVtx, inTrisPtr, numLanes ); + else + GatherVertices( vtxX, vtxY, vtxW, inVtx, inTrisPtr, numLanes, vtxLayout ); + + TransformVerts( vtxX, vtxY, vtxW, modelToClipMatrix ); + + triIndex += SIMD_LANES; + inTrisPtr += SIMD_LANES * 3; + } + + ////////////////////////////////////////////////////////////////////////////// + // Clip transformed triangles + ////////////////////////////////////////////////////////////////////////////// + + if( clipPlaneMask != ClipPlanes::CLIP_PLANE_NONE ) + ClipTriangleAndAddToBuffer( vtxX, vtxY, vtxW, clipTriBuffer, clipHead, triMask, triClipMask, clipPlaneMask ); + } + + void RenderTrilist(const TriList &triList, const ScissorRect *scissor) override + { + assert(mMaskedHiZBuffer != nullptr); + + // Setup fullscreen scissor rect as default + scissor = scissor == nullptr ? &mFullscreenScissor : scissor; + + for (unsigned int i = 0; i < triList.mTriIdx; i += SIMD_LANES) + { + ////////////////////////////////////////////////////////////////////////////// + // Fetch triangle vertices + ////////////////////////////////////////////////////////////////////////////// + + unsigned int numLanes = min((unsigned int)SIMD_LANES, triList.mTriIdx - i); + unsigned int triMask = (1U << numLanes) - 1; + + __mw pVtxX[3], pVtxY[3], pVtxZ[3]; +#if PRECISE_COVERAGE != 0 + __mwi ipVtxX[3], ipVtxY[3]; + for (unsigned int l = 0; l < numLanes; ++l) + { + unsigned int triIdx = i + l; + for (int v = 0; v < 3; ++v) + { + simd_i32(ipVtxX[v])[l] = ((int*)triList.mPtr)[v * 3 + triIdx * 9 + 0]; + simd_i32(ipVtxY[v])[l] = ((int*)triList.mPtr)[v * 3 + triIdx * 9 + 1]; + simd_f32(pVtxZ[v])[l] = triList.mPtr[v * 3 + triIdx * 9 + 2]; + } + } + + for (int v = 0; v < 3; ++v) + { + pVtxX[v] = _mmw_mul_ps(_mmw_cvtepi32_ps(ipVtxX[v]), _mmw_set1_ps(FP_INV)); + pVtxY[v] = _mmw_mul_ps(_mmw_cvtepi32_ps(ipVtxY[v]), _mmw_set1_ps(FP_INV)); + } + + ////////////////////////////////////////////////////////////////////////////// + // Setup and rasterize a SIMD batch of triangles + ////////////////////////////////////////////////////////////////////////////// + + RasterizeTriangleBatch(ipVtxX, ipVtxY, pVtxX, pVtxY, pVtxZ, triMask, scissor); +#else + for (unsigned int l = 0; l < numLanes; ++l) + { + unsigned int triIdx = i + l; + for (int v = 0; v < 3; ++v) + { + simd_f32(pVtxX[v])[l] = triList.mPtr[v * 3 + triIdx * 9 + 0]; + simd_f32(pVtxY[v])[l] = triList.mPtr[v * 3 + triIdx * 9 + 1]; + simd_f32(pVtxZ[v])[l] = triList.mPtr[v * 3 + triIdx * 9 + 2]; + } + } + + ////////////////////////////////////////////////////////////////////////////// + // Setup and rasterize a SIMD batch of triangles + ////////////////////////////////////////////////////////////////////////////// + + RasterizeTriangleBatch(pVtxX, pVtxY, pVtxZ, triMask, scissor); +#endif + + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Debugging and statistics + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + MaskedOcclusionCulling::Implementation GetImplementation() override + { + return gInstructionSet; + } + + void ComputePixelDepthBuffer(float *depthData, bool flipY) override + { + assert(mMaskedHiZBuffer != nullptr); + for (int y = 0; y < mHeight; y++) + { + for (int x = 0; x < mWidth; x++) + { + // Compute 32xN tile index (SIMD value offset) + int tx = x / TILE_WIDTH; + int ty = y / TILE_HEIGHT; + int tileIdx = ty * mTilesWidth + tx; + + // Compute 8x4 subtile index (SIMD lane offset) + int stx = (x % TILE_WIDTH) / SUB_TILE_WIDTH; + int sty = (y % TILE_HEIGHT) / SUB_TILE_HEIGHT; + int subTileIdx = sty * 4 + stx; + + // Compute pixel index in subtile (bit index in 32-bit word) + int px = (x % SUB_TILE_WIDTH); + int py = (y % SUB_TILE_HEIGHT); + int bitIdx = py * 8 + px; + + int pixelLayer = (simd_i32(mMaskedHiZBuffer[tileIdx].mMask)[subTileIdx] >> bitIdx) & 1; + float pixelDepth = simd_f32(mMaskedHiZBuffer[tileIdx].mZMin[pixelLayer])[subTileIdx]; + + if( flipY ) + depthData[( mHeight - y - 1 ) * mWidth + x] = pixelDepth; + else + depthData[y * mWidth + x] = pixelDepth; + } + } + } + + OcclusionCullingStatistics GetStatistics() override + { + return mStats; + } + +}; diff --git a/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/PackageInfo.json b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/PackageInfo.json new file mode 100644 index 0000000000..08b29fd566 --- /dev/null +++ b/Gems/Atom/RPI/Code/External/MaskedOcclusionCulling/PackageInfo.json @@ -0,0 +1,6 @@ +{ + "PackageName": "Masked Occlusion Culling", + "URL": "https://software.intel.com/content/www/us/en/develop/articles/masked-software-occlusion-culling.html", + "License": "Apache 2.0", + "LicenseFile": "LICENSE.txt" +} From afeea878627b29f465eb0da648f06f4e9dbc69b0 Mon Sep 17 00:00:00 2001 From: karlberg Date: Wed, 2 Jun 2021 19:21:39 -0700 Subject: [PATCH 039/153] Fix for linux being a banned keyword --- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index f30c8912de..069ac49d96 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -38,7 +38,7 @@ #include -#include // for std::powf on linux +#include namespace AZ::ConsoleTypeHelpers { @@ -641,7 +641,7 @@ namespace Multiplayer m_renderBlendFactor += targetAdjustBlend; // Linear close to the origin, but asymptote at y = 1 - const float adjustedBlendFactor = 1.0f - (std::powf(0.2f, m_renderBlendFactor)); + const float adjustedBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor)); AZLOG(NET_Blending, "Computed blend factor of %f", adjustedBlendFactor); if (Camera::ActiveCameraRequestBus::HasHandlers()) From 89b1afc50e00e7dd78488feb9ba6770544412d9d Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 2 Jun 2021 19:37:35 -0700 Subject: [PATCH 040/153] Adding Multiplayer:: namespace to RpcIndex so components outside the Multiplayer gem can compile --- Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 5cfd0bfc4d..917b1058a7 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -311,7 +311,7 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(const {{ Prop {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }}) { - constexpr RpcIndex rpcId = static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }}); + constexpr Multiplayer::RpcIndex rpcId = static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }}); {% if Property.attrib['IsReliable']|booleanTrue %} constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Reliable; {% else %} From 69e2d6bba1022f9e439a8c55edf1bbabf89887da Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 19:44:55 -0700 Subject: [PATCH 041/153] Minor comment update --- Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index 7d192ea62a..e611ecf0d6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -202,7 +202,7 @@ namespace AZ MatrixChangedEvent m_onWorldToClipMatrixChange; MatrixChangedEvent m_onWorldToViewMatrixChange; - // Software occlusion culling + // Masked Occlusion Culling interface MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; }; From d737fcd3d3acd03edd184086e0e4b3754f2c6ed2 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 19:52:28 -0700 Subject: [PATCH 042/153] Removed extra newline --- Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 85b6bf07b8..e97805ceb2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -617,7 +617,6 @@ namespace AZ jobData->m_maskedOcclusionCulling = maskedOcclusionCulling; #endif - auto nodeVisitorLambda = [this, jobData, &parentJob, &frustum, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void { AZ_PROFILE_SCOPE(Debug::ProfileCategory::AzRender, "nodeVisitorLambda()"); From 113073ca31fcf10b9d2d1ff8e02962c5264c9ff9 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 19:54:22 -0700 Subject: [PATCH 043/153] Removed unnecessary include --- Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index c02ac0713c..7e33750eb5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include From b09f73378f3efc08f7fa775e1f49bd38b30f63f3 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 20:49:39 -0700 Subject: [PATCH 044/153] [cpack_installer] replaced LY_DEFAULT_INSTALL_COMPONENT with built-in CMAKE_INSTALL_DEFAULT_COMPONENT_NAME. updated stale references to ly_install_target_COMPONENT with a get_prop call --- cmake/3rdParty.cmake | 2 - cmake/Packaging.cmake | 4 +- cmake/Platform/Common/Install_common.cmake | 46 ++++++++-------------- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index eb11404237..ebf640af23 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -291,7 +291,6 @@ function(ly_install_external_target 3RDPARTY_ROOT_DIRECTORY) # Install the Find file to our /cmake directory install(FILES ${CMAKE_CURRENT_LIST_FILE} DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # We only want to install external targets that are part of our source tree @@ -302,7 +301,6 @@ function(ly_install_external_target 3RDPARTY_ROOT_DIRECTORY) get_filename_component(rel_path ${rel_path} DIRECTORY) install(DIRECTORY ${3RDPARTY_ROOT_DIRECTORY} DESTINATION ${rel_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endif() diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e7136eab12..1bcb251271 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -101,7 +101,7 @@ endif() install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # IMPORTANT: required to be included AFTER setting all property overrides @@ -141,7 +141,7 @@ endfunction() # configure ALL components here ly_configure_cpack_component( - ${LY_DEFAULT_INSTALL_COMPONENT} REQUIRED + ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} REQUIRED DISPLAY_NAME "${PROJECT_NAME} Core" DESCRIPTION "${PROJECT_NAME} Headers, Libraries and Tools" ) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 710a8b266f..e0301bb914 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -11,7 +11,7 @@ set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise -ly_set(LY_DEFAULT_INSTALL_COMPONENT Core) +ly_set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Core) file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) @@ -27,6 +27,12 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) # De-alias target name ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) + # get the component ID. if the property isn't set for the target, fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_target_property(install_componet ${TARGET_NAME} INSTALL_COMPONENT) + if("${install_componet}" STREQUAL "install_componet-NOTFOUND") + unset(install_componet) + endif() + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. @@ -41,7 +47,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) unset(current_public_headers) install(DIRECTORY ${include_directory} DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -68,13 +74,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} LIBRARY DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) # CMakeLists.txt file @@ -182,7 +188,7 @@ set_property(TARGET ${TARGET_NAME} file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target @@ -239,9 +245,13 @@ function(ly_setup_subdirectory absolute_target_source_dir) "\n" "${CREATE_ALIASES_PLACEHOLDER}" ) + + # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_property(install_componet DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} + COMPONENT ${install_componet} ) endfunction() @@ -262,7 +272,6 @@ function(ly_setup_cmake_install) install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE REGEX "Findo3de.cmake" EXCLUDE REGEX "Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE @@ -290,7 +299,6 @@ function(ly_setup_cmake_install) "${LY_ROOT_FOLDER}/CMakeLists.txt" "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Collect all Find files that were added with ly_add_external_target_path @@ -303,7 +311,6 @@ function(ly_setup_cmake_install) endforeach() install(FILES ${additional_find_files} DESTINATION cmake/3rdParty - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all @@ -320,7 +327,6 @@ function(ly_setup_cmake_install) configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect @@ -340,7 +346,6 @@ function(ly_setup_cmake_install) ) install(FILES "${pal_builtin_file}" DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -362,7 +367,6 @@ endfunction() function(ly_copy source_file target_directory) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endfunction()" - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) unset(runtime_commands) @@ -408,7 +412,6 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file install(CODE "${runtime_commands_str}" - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -427,7 +430,6 @@ function(ly_setup_others) install(DIRECTORY "${LY_ROOT_FOLDER}/${dir}" DESTINATION ${install_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE ) @@ -438,7 +440,6 @@ function(ly_setup_others) install(FILES ${o3de_scripts} DESTINATION ./scripts - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY @@ -446,7 +447,6 @@ function(ly_setup_others) ${LY_ROOT_FOLDER}/scripts/project_manager ${LY_ROOT_FOLDER}/scripts/o3de DESTINATION ./scripts - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE PATTERN "CMakeLists.txt" EXCLUDE PATTERN "tests" EXCLUDE @@ -454,7 +454,6 @@ function(ly_setup_others) install(DIRECTORY "${LY_ROOT_FOLDER}/python" DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} REGEX "downloaded_packages" EXCLUDE REGEX "runtime" EXCLUDE ) @@ -463,19 +462,16 @@ function(ly_setup_others) install(DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry DESTINATION ./${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY ${LY_ROOT_FOLDER}/Registry DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Engine Source Assets install(DIRECTORY ${LY_ROOT_FOLDER}/Assets DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Gem Source Assets and Registry @@ -495,7 +491,6 @@ function(ly_setup_others) # the "Assets" folder from being copied underneath the /Assets folder install(DIRECTORY ${gem_abs_assets_path} DESTINATION ${gem_assets_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endif() endforeach() @@ -511,7 +506,6 @@ function(ly_setup_others) get_filename_component(gem_relative_path ${gem_json_path} DIRECTORY) install(FILES ${gem_json_path} DESTINATION ${gem_relative_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endforeach() @@ -519,14 +513,12 @@ function(ly_setup_others) install(DIRECTORY ${LY_ROOT_FOLDER}/Gems/Atom/Asset/ImageProcessingAtom/Config DESTINATION Gems/Atom/Asset/ImageProcessingAtom - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Templates install(DIRECTORY ${LY_ROOT_FOLDER}/Templates DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Misc @@ -535,7 +527,6 @@ function(ly_setup_others) ${LY_ROOT_FOLDER}/LICENSE.txt ${LY_ROOT_FOLDER}/README.md DESTINATION . - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() @@ -549,15 +540,12 @@ function(ly_setup_target_generator) ${LY_ROOT_FOLDER}/Code/LauncherUnified/LauncherProject.cpp ${LY_ROOT_FOLDER}/Code/LauncherUnified/StaticModules.in DESTINATION LauncherGenerator - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY ${LY_ROOT_FOLDER}/Code/LauncherUnified/Platform DESTINATION LauncherGenerator - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(FILES ${LY_ROOT_FOLDER}/Code/LauncherUnified/FindLauncherGenerator.cmake DESTINATION cmake - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() From 99497672f4188479a92f45411ee66a09012c23ec Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 20:51:07 -0700 Subject: [PATCH 045/153] Fixed cmake platform files for non-Windows platforms --- .../Code/Source/Platform/Android/platform_android_files.cmake | 4 ++-- .../RPI/Code/Source/Platform/Linux/platform_linux_files.cmake | 4 ++-- .../RPI/Code/Source/Platform/Mac/platform_mac_files.cmake | 4 ++-- .../RPI/Code/Source/Platform/iOS/platform_ios_files.cmake | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake index 357d8f0381..83ddc410d6 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/platform_android_files.cmake @@ -10,6 +10,6 @@ # set(FILES - Atom_Feature_Traits_Platform.h - Atom_Feature_Traits_Android.h + Atom_RPI_Traits_Platform.h + Atom_RPI_Traits_Android.h ) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake index 19be7951f6..99df861f9c 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/platform_linux_files.cmake @@ -10,6 +10,6 @@ # set(FILES - Atom_Feature_Traits_Platform.h - Atom_Feature_Traits_Linux.h + Atom_RPI_Traits_Platform.h + Atom_RPI_Traits_Linux.h ) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake index bde67ff340..b1baca036e 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/platform_mac_files.cmake @@ -10,6 +10,6 @@ # set(FILES - Atom_Feature_Traits_Platform.h - Atom_Feature_Traits_Mac.h + Atom_RPI_Traits_Platform.h + Atom_RPI_Traits_Mac.h ) diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake index 7f603e4bfd..3eae72e612 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/platform_ios_files.cmake @@ -10,6 +10,6 @@ # set(FILES - Atom_Feature_Traits_Platform.h - Atom_Feature_Traits_iOS.h + Atom_RPI_Traits_Platform.h + Atom_RPI_Traits_iOS.h ) From 9afd9b0992befcd19390cea11ec74bdb0080103a Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 20:58:22 -0700 Subject: [PATCH 046/153] Fixed PAL cmake files for non-Windows builds --- .../Code/Source/Platform/Android/PAL_android.cmake | 13 +++++++++++++ .../RPI/Code/Source/Platform/Linux/PAL_linux.cmake | 1 + .../Atom/RPI/Code/Source/Platform/Mac/PAL_mac.cmake | 1 + .../Atom/RPI/Code/Source/Platform/iOS/PAL_ios.cmake | 13 +++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 Gems/Atom/RPI/Code/Source/Platform/Android/PAL_android.cmake create mode 100644 Gems/Atom/RPI/Code/Source/Platform/iOS/PAL_ios.cmake diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/PAL_android.cmake b/Gems/Atom/RPI/Code/Source/Platform/Android/PAL_android.cmake new file mode 100644 index 0000000000..4542e7c707 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/PAL_android.cmake @@ -0,0 +1,13 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED FALSE) +set (PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED FALSE) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/PAL_linux.cmake b/Gems/Atom/RPI/Code/Source/Platform/Linux/PAL_linux.cmake index e9a14ba928..4542e7c707 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Linux/PAL_linux.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/PAL_linux.cmake @@ -10,3 +10,4 @@ # set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED FALSE) +set (PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED FALSE) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/PAL_mac.cmake b/Gems/Atom/RPI/Code/Source/Platform/Mac/PAL_mac.cmake index c060b8bbaa..f177b9dfb9 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Mac/PAL_mac.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/PAL_mac.cmake @@ -10,3 +10,4 @@ # set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED TRUE) +set (PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED FALSE) diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/PAL_ios.cmake b/Gems/Atom/RPI/Code/Source/Platform/iOS/PAL_ios.cmake new file mode 100644 index 0000000000..4542e7c707 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/PAL_ios.cmake @@ -0,0 +1,13 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +set (PAL_TRAIT_BUILD_ATOM_RPI_ASSETS_SUPPORTED FALSE) +set (PAL_TRAIT_BUILD_ATOM_RPI_MASKED_OCCLUSION_CULLING_SUPPORTED FALSE) From 5695681ed3518d3e7c4ab7ed3aad92c4bb01d422 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 21:03:41 -0700 Subject: [PATCH 047/153] [cpack_installer] fifth attempt to fix cpack selection --- scripts/build/Platform/Windows/installer_windows.cmd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index 73d1a3d88c..c71b091de9 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -29,22 +29,25 @@ IF NOT EXIST "%WIX_TEMP%" ( REM Make sure we are using the CMake version of CPack and not the one that comes with chocolatey SET CPACK_PATH= IF "%LY_CMAKE_PATH%"=="" ( - FOR /F %%i in ('where cpack') DO ( + REM quote the paths from 'where' so we can properly tokenize ones in the list with spaces + FOR /F delims^=^"^ tokens^=1 %%i in ('where /F cpack') DO ( REM The cpack in chocolatey expects a number supplied with --version so it will error "%%i" --version > NUL IF !ERRORLEVEL!==0 ( SET "CPACK_PATH=%%i" + GOTO :run_cpack ) ) ) ELSE ( SET "CPACK_PATH=%LY_CMAKE_PATH%\cpack.exe" ) +:run_cpack ECHO [ci_build] "!CPACK_PATH!" --version "!CPACK_PATH!" --version IF ERRORLEVEL 1 ( ECHO [ci_build] CPack not found! - exit /b 1 + GOTO :popd_error ) ECHO [ci_build] "!CPACK_PATH!" -C %CONFIGURATION% From 091d6894cb928d51d61a6d026b6854ca304da47b Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Wed, 2 Jun 2021 22:02:10 -0700 Subject: [PATCH 048/153] Fixed non-Windows platform include --- .../RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h | 2 +- .../RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h | 2 +- .../RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h | 2 +- .../RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h index 27e0af7f35..60835c7025 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h +++ b/Gems/Atom/RPI/Code/Source/Platform/Android/Atom_RPI_Traits_Platform.h @@ -11,4 +11,4 @@ */ #pragma once -#include "Atom_Feature_Traits_Android.h" +#include "Atom_RPI_Traits_Android.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h index 39c6a3e572..f7a51ddbf7 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h +++ b/Gems/Atom/RPI/Code/Source/Platform/Linux/Atom_RPI_Traits_Platform.h @@ -11,4 +11,4 @@ */ #pragma once -#include "Atom_Feature_Traits_Linux.h" +#include "Atom_RPI_Traits_Linux.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h index 19816f2bd1..87bc2190f3 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h +++ b/Gems/Atom/RPI/Code/Source/Platform/Mac/Atom_RPI_Traits_Platform.h @@ -11,4 +11,4 @@ */ #pragma once -#include "Atom_Feature_Traits_Mac.h" +#include "Atom_RPI_Traits_Mac.h" diff --git a/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h index 4403d741dc..48fe26cc61 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h +++ b/Gems/Atom/RPI/Code/Source/Platform/iOS/Atom_RPI_Traits_Platform.h @@ -11,4 +11,4 @@ */ #pragma once -#include "Atom_Feature_Traits_iOS.h" +#include "Atom_RPI_Traits_iOS.h" From 602dd01434848ad04e32123e1dbd6d0aeb717824 Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 22:02:11 -0700 Subject: [PATCH 049/153] [cpack_installer] fixed typo in error message --- cmake/Packaging.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 1bcb251271..e2aa0f9348 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -54,7 +54,7 @@ endif() if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) message(FATAL_ERROR "The desired version of CMake to be included in the package is " - "is below the minium required version of CMake to run") + "is below the minimum required version of CMake to run") endif() # pull down the desired copy of CMake so it can be included in the package From 881c51dc9c9ff3caa1f4b404c91e9cbaf74bd6ab Mon Sep 17 00:00:00 2001 From: scottr Date: Wed, 2 Jun 2021 22:05:20 -0700 Subject: [PATCH 050/153] [cpack_installer] removed unnecessary explicit use of CMAKE_INSTALL_DEFAULT_COMPONENT_NAME --- cmake/Packaging.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e2aa0f9348..e5799c8ff1 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -101,7 +101,6 @@ endif() install(FILES ${_cmake_package_dest} DESTINATION ./Tools/Redistributables/CMake - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) # IMPORTANT: required to be included AFTER setting all property overrides From f2a7cd9a2da207c118ae56f58dd8077f3d1960dd Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Thu, 3 Jun 2021 08:29:24 -0500 Subject: [PATCH 051/153] Fixed monolithic build warning/error (#1116) --- Gems/LyShine/Code/Source/LyShineSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 0eab7705f6..1290683145 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -375,7 +375,7 @@ namespace LyShine } /////////////////////////////////////////////////////////////////////////////////////////////// - void LyShineSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]] const SSystemInitParams& startupParams) + void LyShineSystemComponent::OnCrySystemInitialized([[maybe_unused]] ISystem& system, [[maybe_unused]] const SSystemInitParams& startupParams) { #if !defined(AZ_MONOLITHIC_BUILD) // When module is linked dynamically, we must set our gEnv pointer. From 328ced0059f90f66d740d97e2f50721c9724995f Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 07:24:30 -0700 Subject: [PATCH 052/153] [cpack_installer] replaced missing get_target_property hack and fixed a typo --- cmake/Platform/Common/Install_common.cmake | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index e0301bb914..7e6917287f 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -27,11 +27,8 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) # De-alias target name ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - # get the component ID. if the property isn't set for the target, fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME - get_target_property(install_componet ${TARGET_NAME} INSTALL_COMPONENT) - if("${install_componet}" STREQUAL "install_componet-NOTFOUND") - unset(install_componet) - endif() + # get the component ID. if the property isn't set for the target, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + get_property(install_component TARGET ${TARGET_NAME} PROPERTY INSTALL_COMPONENT) # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the @@ -47,7 +44,7 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) unset(current_public_headers) install(DIRECTORY ${include_directory} DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} FILES_MATCHING PATTERN *.h PATTERN *.hpp @@ -74,13 +71,13 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${install_componet} + COMPONENT ${install_component} LIBRARY DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${install_componet} + COMPONENT ${install_component} RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) # CMakeLists.txt file @@ -188,7 +185,7 @@ set_property(TARGET ${TARGET_NAME} file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" DESTINATION ${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target @@ -247,11 +244,11 @@ function(ly_setup_subdirectory absolute_target_source_dir) ) # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME - get_property(install_componet DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) + get_property(install_component DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" DESTINATION ${target_source_dir} - COMPONENT ${install_componet} + COMPONENT ${install_component} ) endfunction() From cf08f4dab1e7206a8b69e7d79b5f1f0a4b51e398 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Thu, 3 Jun 2021 15:48:44 +0100 Subject: [PATCH 053/153] Improve camera orbit behavior (#1060) --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 18 +++++++-------- .../SandboxIntegration.cpp | 7 +++--- .../ModularViewportCameraController.h | 5 ++++- ...odularViewportCameraControllerRequestBus.h | 7 +++++- .../ModularViewportCameraController.cpp | 22 +++++++++++++++++-- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 24d1590808..667179e3cd 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -1233,7 +1233,7 @@ void EditorViewportWidget::SetViewportId(int id) auto controller = AZStd::make_shared(); controller->SetCameraListBuilderCallback( - [](AzFramework::Cameras& cameras) + [id](AzFramework::Cameras& cameras) { auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::CameraFreeLookButton); auto firstPersonPanCamera = @@ -1243,17 +1243,17 @@ void EditorViewportWidget::SetViewportId(int id) auto orbitCamera = AZStd::make_shared(); orbitCamera->SetLookAtFn( - [](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional + [id](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional { - AZStd::optional manipulatorTransform; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - manipulatorTransform, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); + AZStd::optional lookAtAfterInterpolation; + AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult( + lookAtAfterInterpolation, id, + &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation); - // initially attempt to use manipulator transform if one exists (there is a selection) - if (manipulatorTransform) + // initially attempt to use the last set look at point after an interpolation has finished + if (lookAtAfterInterpolation.has_value()) { - return manipulatorTransform->GetTranslation(); + return *lookAtAfterInterpolation; } const float RayDistance = 1000.0f; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 5ff2debe3d..8161d07547 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1732,13 +1732,14 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework:: // compute new camera transform const float fov = AzFramework::RetrieveFov(viewportContext->GetCameraProjectionMatrix()); const float fovScale = (1.0f / AZStd::tan(fov * 0.5f)); - const float distanceToTarget = selectionSize * fovScale * centerScale; + const float distanceToLookAt = selectionSize * fovScale * centerScale; const AZ::Transform nextCameraTransform = - AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToTarget), aabb.GetCenter()); + AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToLookAt), aabb.GetCenter()); AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( viewportContext->GetId(), - &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform); + &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform, + distanceToLookAt); } } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 1318deb355..b88b340926 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -51,7 +51,8 @@ namespace AtomToolsFramework void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; // ModularViewportCameraControllerRequestBus overrides ... - void InterpolateToTransform(const AZ::Transform& worldFromLocal) override; + void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override; + AZStd::optional LookAtAfterInterpolation() const override; private: // AzFramework::ViewportDebugDisplayEventBus overrides ... @@ -71,6 +72,8 @@ namespace AtomToolsFramework AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); float m_animationT = 0.0f; CameraMode m_cameraMode = CameraMode::Control; + AZStd::optional m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished. + //!< Will be cleared when the view changes (camera looks away). bool m_updatingTransform = false; AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h index 5b90119372..a7f067cdf4 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -32,7 +32,12 @@ namespace AtomToolsFramework static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; //! Begin a smooth transition of the camera to the requested transform. - virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0; + //! @param worldFromLocal The transform of where the camera should end up. + //! @param lookAtDistance The distance between the camera transform and the imagined look at point. + virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0; + + //! Look at point after an interpolation has finished and no translation has occurred. + virtual AZStd::optional LookAtAfterInterpolation() const = 0; protected: ~ModularViewportCameraControllerRequests() = default; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 896d9f8043..082dc8f272 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -140,6 +140,18 @@ namespace AtomToolsFramework m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count()); m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, event.m_deltaTime.count()); + // if there has been an interpolation, only clear the look at point if it is no longer + // centered in the view (the camera has looked away from it) + if (m_lookAtAfterInterpolation.has_value()) + { + if (const float lookDirection = + (*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY()); + !AZ::IsCloseMag(lookDirection, 1.0f, 0.001f)) + { + m_lookAtAfterInterpolation = {}; + } + } + viewportContext->SetCameraTransform(m_camera.Transform()); } else if (m_cameraMode == CameraMode::Animation) @@ -148,8 +160,8 @@ namespace AtomToolsFramework { return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); }; - const float transitionT = smootherStepFn(m_animationT); + const float transitionT = smootherStepFn(m_animationT); const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation( m_transformStart.GetRotation().Slerp(m_transformEnd.GetRotation(), transitionT), m_transformStart.GetTranslation().Lerp(m_transformEnd.GetTranslation(), transitionT)); @@ -185,11 +197,17 @@ namespace AtomToolsFramework } } - void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal) + void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance) { m_animationT = 0.0f; m_cameraMode = CameraMode::Animation; m_transformStart = m_camera.Transform(); m_transformEnd = worldFromLocal; + m_lookAtAfterInterpolation = m_transformEnd.GetTranslation() + m_transformEnd.GetBasisY() * lookAtDistance; + } + + AZStd::optional ModernViewportCameraControllerInstance::LookAtAfterInterpolation() const + { + return m_lookAtAfterInterpolation; } } // namespace AtomToolsFramework From 8214706ff9ab2c49cfafc7164bb6dbe0d296112c Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 08:24:01 -0700 Subject: [PATCH 054/153] [cpack_installer] reworked how packaging is enabled for windows --- cmake/Platform/Windows/Packaging_windows.cmake | 10 ++-------- scripts/build/Platform/Windows/build_config.json | 3 +-- scripts/build/Platform/Windows/build_windows.cmd | 8 -------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index 5210c24e7b..2fd281ad51 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -9,17 +9,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(LY_WIX_PATH "" CACHE PATH "Path to the WiX install path") - -if(LY_WIX_PATH) - file(TO_CMAKE_PATH ${LY_WIX_PATH} CPACK_WIX_ROOT) -elseif(DEFINED ENV{WIX}) - file(TO_CMAKE_PATH $ENV{WIX} CPACK_WIX_ROOT) -endif() +set(CPACK_WIX_ROOT "" CACHE PATH "Path to the WiX install path") if(CPACK_WIX_ROOT) if(NOT EXISTS ${CPACK_WIX_ROOT}) - message(FATAL_ERROR "Invalid path supplied for LY_WIX_PATH argument or WIX environment variable") + message(FATAL_ERROR "Invalid path supplied for CPACK_WIX_ROOT argument") endif() else() # early out as no path to WiX has been supplied effectively disabling support diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index b0d16f1fb6..fc4668de0a 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -314,8 +314,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE", - "CMAKE_INCLUDE_WIX": "True", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCPACK_WIX_ROOT=\"!WIX!\"", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 799e6828b2..3e995e1905 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -38,14 +38,6 @@ IF NOT EXIST %TMP% ( REM Compute half the amount of processors so some jobs can run SET /a HALF_PROCESSORS = NUMBER_OF_PROCESSORS / 2 -IF "%CMAKE_INCLUDE_WIX%"=="True" ( - REM Explicitly enable wix via command line arg for forensic logging - SET CMAKE_OPTIONS=%CMAKE_OPTIONS% -DLY_WIX_PATH="%WIX%" -) ELSE ( - REM Disable implicit enabling of windows packing by clearing out the wix variable - SET WIX= -) - SET LAST_CONFIGURE_CMD_FILE=ci_last_configure_cmd.txt SET CONFIGURE_CMD=cmake %SOURCE_DIRECTORY% %CMAKE_OPTIONS% %EXTRA_CMAKE_OPTIONS% -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" -DLY_PROJECTS=%CMAKE_LY_PROJECTS% IF NOT EXIST CMakeCache.txt ( From cd619e14dc9b74f845cb4897780ea8aa6004f10b Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 3 Jun 2021 08:31:38 -0700 Subject: [PATCH 055/153] Allow script canvas users to send RPCs via entityId --- .../Source/AutoGen/AutoComponent_Common.jinja | 2 +- .../Source/AutoGen/AutoComponent_Source.jinja | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index 61dcacaa94..05403a00ef 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -175,7 +175,7 @@ void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ //! {{ PropertyName }} Handler //! {{ Property.attrib['Description'] }} //! HandleOn {{ HandleOn }} -virtual void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) = 0; +virtual void Handle{{ PropertyName }}([[maybe_unused]] AzNetworking::IConnection* invokingConnection, [[maybe_unused]] {{ ', [[maybe_unused]] '.join(paramDefines) }}) {} {% endif %} {% endmacro %} {# diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 917b1058a7..259f469020 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -368,6 +368,31 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo ->Method("{{ UpperFirst(Property.attrib['Name']) }}", [](const {{ ClassName }}* self, {{ ', '.join(paramDefines) }}) { self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); }) + ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntity", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) { + + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); + if (!entity) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) + return; + } + + {{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>(); + if (!networkComponent) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) + return; + } + + {{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController()); + if (!controller) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str()) + return; + } + + controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); + }) {% endif %} {% endcall %} {% endmacro %} From 5fbf587b9e34a88a7b26d8ccbde77f6ae9fa15a4 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 10:50:27 -0500 Subject: [PATCH 056/153] Updating File Menu actions in test_Menus_FileMenuOptions_Work. Temporarily marking test as xfail due to LYN-4208 --- .../EditorScripts/Menus_FileMenuOptions.py | 10 ++++----- .../Gem/PythonTests/editor/test_Menus.py | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py index 3e174af2bd..734226a9d1 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py @@ -9,11 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ -""" -C24064528: The File menu options function normally -C16780778: The File menu options function normally-New view interaction Model enabled -""" - import os import sys @@ -54,7 +49,10 @@ class TestFileMenuOptions(EditorTestHelper): ("Save",), ("Save As",), ("Save Level Statistics",), - ("Project Settings", "Project Settings Tool"), + ("Edit Project Settings",), + ("Edit Platform Settings",), + ("New Project",), + ("Open Project",), ("Show Log File",), ("Resave All Slices",), ("Exit",), diff --git a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py index c2da1343de..2b3fdcbdf3 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py +++ b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py @@ -7,8 +7,6 @@ distribution (the "License"). All use of this software is governed by the Licens or, if provided, by the license below or the license accompanying this file. Do not remove or modify any license notices. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -C16780783: Base Edit Menu Options (New Viewport Interaction Model) """ import os @@ -17,6 +15,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools.environment.process_utils as process_utils import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts") @@ -33,6 +32,7 @@ class TestMenus(object): def setup_teardown(self, request, workspace, project, level): def teardown(): file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) + process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows request.addfinalizer(teardown) @@ -80,8 +80,7 @@ class TestMenus(object): expected_lines, cfg_args=[level], run_python="--runpython", - auto_test_mode=True, - timeout=log_monitor_timeout, + timeout=log_monitor_timeout ) @pytest.mark.test_case_id("C16780807") @@ -107,13 +106,13 @@ class TestMenus(object): "Menus_ViewMenuOptions.py", expected_lines, cfg_args=[level], - auto_test_mode=True, run_python="--runpython", - timeout=log_monitor_timeout, + timeout=log_monitor_timeout ) @pytest.mark.test_case_id("C16780778") @pytest.mark.SUITE_sandbox + @pytest.mark.xfail # LYN-4208 def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform): expected_lines = [ "New Level Action triggered", @@ -122,7 +121,10 @@ class TestMenus(object): "Save Action triggered", "Save As Action triggered", "Save Level Statistics Action triggered", - "Project Settings Tool Action triggered", + "Edit Project Settings Action triggered", + "Edit Platform Settings Action triggered", + "New Project Action triggered", + "Open Project Action triggered", "Show Log File Action triggered", "Resave All Slices Action triggered", "Exit Action triggered", @@ -135,7 +137,6 @@ class TestMenus(object): "Menus_FileMenuOptions.py", expected_lines, cfg_args=[level], - auto_test_mode=True, run_python="--runpython", - timeout=log_monitor_timeout, - ) \ No newline at end of file + timeout=log_monitor_timeout + ) From 29c71b4e530861d07426521a574f168d781a2ca3 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 3 Jun 2021 09:30:33 -0700 Subject: [PATCH 057/153] SPEC-2513 Fixes to enable w4701 (#1105) * Some fixes * more fixes * fixes for debug --- Code/CryEngine/CrySystem/DebugCallStack.cpp | 2 +- Code/CryEngine/CrySystem/System.cpp | 2 +- Code/CryEngine/CrySystem/SystemInit.cpp | 2 +- Code/Framework/AzCore/Tests/Jobs.cpp | 3 ++- .../Windowing/NativeWindow_Windows.cpp | 1 + Code/Sandbox/Editor/LogFile.cpp | 2 +- Code/Sandbox/Editor/Util/AffineParts.cpp | 4 ++-- Code/Sandbox/Editor/Util/FileUtil.cpp | 3 ++- Code/Sandbox/Editor/Util/ImageBT.cpp | 1 + Code/Sandbox/Editor/Util/StringHelpers.cpp | 2 +- .../Code/Source/Converters/FIR-Weights.cpp | 2 +- .../External/CubeMapGen/CCubeMapProcessor.cpp | 2 +- .../Code/Source/RHI/FrameGraphCompiler.cpp | 1 + .../Code/Tests/BoolLogicNodeTests.cpp | 4 ++-- .../Code/External/FastNoise/FastNoise.cpp | 21 +++++++++++++------ .../GraphCanvas/Utils/GraphUtils.cpp | 2 +- .../Code/Source/Animation/AzEntityNode.cpp | 2 +- .../Code/Source/UiLayoutGridComponent.cpp | 6 ++++-- .../Code/Source/UiNavigationHelpers.cpp | 2 ++ .../Source/Optimization/LineSearch.cpp | 2 +- .../Common/MSVC/Configurations_msvc.cmake | 1 - 21 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Code/CryEngine/CrySystem/DebugCallStack.cpp b/Code/CryEngine/CrySystem/DebugCallStack.cpp index 2a219ce674..eea4725639 100644 --- a/Code/CryEngine/CrySystem/DebugCallStack.cpp +++ b/Code/CryEngine/CrySystem/DebugCallStack.cpp @@ -561,7 +561,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex) if (pex) { - MINIDUMP_TYPE mdumpValue; + MINIDUMP_TYPE mdumpValue = MiniDumpNormal; bool bDump = true; switch (g_cvars.sys_dump_type) { diff --git a/Code/CryEngine/CrySystem/System.cpp b/Code/CryEngine/CrySystem/System.cpp index 6fcbc32b72..bf34700c39 100644 --- a/Code/CryEngine/CrySystem/System.cpp +++ b/Code/CryEngine/CrySystem/System.cpp @@ -66,7 +66,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } if (pSystem && !pSystem->IsQuitting()) { - LRESULT result; + LRESULT result = 0; bool bAny = false; for (std::vector::const_iterator it = pSystem->m_windowMessageHandlers.begin(); it != pSystem->m_windowMessageHandlers.end(); ++it) { diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 52744519bb..4a4296bbb5 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -634,7 +634,7 @@ ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const ch IConsole* pConsole = GetIConsole(); ICVar* pOldVar = pConsole->GetCVar (szVarName); - int nDefault; + int nDefault = 0; if (pOldVar) { nDefault = pOldVar->GetIVal(); diff --git a/Code/Framework/AzCore/Tests/Jobs.cpp b/Code/Framework/AzCore/Tests/Jobs.cpp index 553123496e..664b163417 100644 --- a/Code/Framework/AzCore/Tests/Jobs.cpp +++ b/Code/Framework/AzCore/Tests/Jobs.cpp @@ -395,7 +395,8 @@ namespace UnitTest } else { - int result1, result2; + int result1 = 0; + int result2 = 0; Job* job1 = aznew FibonacciJob2(m_n - 1, &result1, m_context); Job* job2 = aznew FibonacciJob2(m_n - 2, &result2, m_context); StartAsChild(job1); diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp index fd49f37dc8..b96ec81b5f 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp @@ -353,6 +353,7 @@ namespace AzFramework // Get the dimensions of the display device on which the window is currently displayed. MONITORINFO monitorInfo; + memset(&monitorInfo, 0, sizeof(MONITORINFO)); // C4701 potentially uninitialized local variable 'monitorInfo' used monitorInfo.cbSize = sizeof(MONITORINFO); const BOOL success = monitor ? GetMonitorInfo(monitor, &monitorInfo) : FALSE; if (!success) diff --git a/Code/Sandbox/Editor/LogFile.cpp b/Code/Sandbox/Editor/LogFile.cpp index 0841a6b288..0bbfd09a21 100644 --- a/Code/Sandbox/Editor/LogFile.cpp +++ b/Code/Sandbox/Editor/LogFile.cpp @@ -553,7 +553,7 @@ void CLogFile::OnWriteToConsole(const char* sText, bool bNewLine) // remember selection and the top row int len = m_hWndEditBox->document()->toPlainText().length(); - int top; + int top = 0; int from = m_hWndEditBox->textCursor().selectionStart(); int to = from + m_hWndEditBox->textCursor().selectionEnd(); bool keepPos = false; diff --git a/Code/Sandbox/Editor/Util/AffineParts.cpp b/Code/Sandbox/Editor/Util/AffineParts.cpp index e294f93089..139519c078 100644 --- a/Code/Sandbox/Editor/Util/AffineParts.cpp +++ b/Code/Sandbox/Editor/Util/AffineParts.cpp @@ -157,7 +157,7 @@ static Quatern Qt_FromMatrix(HMatrix mat) * |w| is greater than 1/2, which is as small as a largest component can be. * Otherwise, the largest diagonal entry corresponds to the largest of |x|, * |y|, or |z|, one of which must be larger than |w|, and at least 1/2. */ - Quatern qu; + Quatern qu = { 0.0f, 0.0f, 0.0f, 1.0f }; double tr, s; tr = mat[X][X] + mat[Y][Y] + mat[Z][Z]; @@ -531,7 +531,7 @@ Quatern snuggle(Quatern q, HVect* k) #define swap(a, i, j) {a[3] = a[i]; a[i] = a[j]; a[j] = a[3]; } #define cycle(a, p) if (p) {a[3] = a[0]; a[0] = a[1]; a[1] = a[2]; a[2] = a[3]; } \ else {a[3] = a[2]; a[2] = a[1]; a[1] = a[0]; a[0] = a[3]; } - Quatern p; + Quatern p = { 0.0f, 0.0f, 0.0f, 1.0f }; float ka[4]; int i, turn = -1; ka[X] = k->x; diff --git a/Code/Sandbox/Editor/Util/FileUtil.cpp b/Code/Sandbox/Editor/Util/FileUtil.cpp index 8dd379f096..ece516659e 100644 --- a/Code/Sandbox/Editor/Util/FileUtil.cpp +++ b/Code/Sandbox/Editor/Util/FileUtil.cpp @@ -2239,7 +2239,8 @@ uint32 CFileUtil::GetAttributes(const char* filename, bool bUseSourceControl /*= bool CFileUtil::CompareFiles(const QString& strFilePath1, const QString& strFilePath2) { // Get the size of both files. If either fails we say they are different (most likely one doesn't exist) - uint64 size1, size2; + uint64 size1 = 0; + uint64 size2 = 0; if (!GetDiskFileSize(strFilePath1.toUtf8().data(), size1) || !GetDiskFileSize(strFilePath2.toUtf8().data(), size2)) { return false; diff --git a/Code/Sandbox/Editor/Util/ImageBT.cpp b/Code/Sandbox/Editor/Util/ImageBT.cpp index 30c4911cb8..79ce4bba35 100644 --- a/Code/Sandbox/Editor/Util/ImageBT.cpp +++ b/Code/Sandbox/Editor/Util/ImageBT.cpp @@ -116,6 +116,7 @@ bool CImageBT::Load(const QString& fileName, CFloatImage& image) // Get the BT header data BtHeader header; + memset(&header, 0, sizeof(BtHeader)); // C4701 potentially uninitialized local variable 'header' used bool validData = true; validData = validData && (fread(&header, sizeof(BtHeader), 1, file) != 0); diff --git a/Code/Sandbox/Editor/Util/StringHelpers.cpp b/Code/Sandbox/Editor/Util/StringHelpers.cpp index 5e44c3b0bd..12865dfe73 100644 --- a/Code/Sandbox/Editor/Util/StringHelpers.cpp +++ b/Code/Sandbox/Editor/Util/StringHelpers.cpp @@ -419,7 +419,7 @@ static inline bool MatchesWildcardsIgnoreCaseExt_Tpl(const TS& str, const TS& wi const typename TS::value_type* savedStrBegin = 0; const typename TS::value_type* savedStrEnd = 0; const typename TS::value_type* savedWild = 0; - size_t savedWildCount; + size_t savedWildCount = 0; const typename TS::value_type* pStr = str.c_str(); const typename TS::value_type* pWild = wildcards.c_str(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/FIR-Weights.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/FIR-Weights.cpp index 192c82c165..b1d0cfbda0 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/FIR-Weights.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Converters/FIR-Weights.cpp @@ -88,7 +88,7 @@ namespace ImageProcessingAtom int dstPosition; signed short int n; bool trimZeros = true, stillzero; - int lastnonzero, hWeight, highest; + int lastnonzero = 0, hWeight, highest = 0; signed int sumiWeights, iWeight; signed short int* weightsPtr; signed short int* weightsMem; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/External/CubeMapGen/CCubeMapProcessor.cpp b/Gems/Atom/Asset/ImageProcessingAtom/External/CubeMapGen/CCubeMapProcessor.cpp index 26768f8f2e..df31067af0 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/External/CubeMapGen/CCubeMapProcessor.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/External/CubeMapGen/CCubeMapProcessor.cpp @@ -1106,7 +1106,7 @@ namespace ImageProcessingAtom //fractional amount to apply change in tap intensity along edge to taps // in a perpendicular direction to edge CP_ITYPE fixupFrac = (CP_ITYPE)(fixupDist - iFixup) / (CP_ITYPE)(fixupDist); - CP_ITYPE fixupWeight; + CP_ITYPE fixupWeight = 0.0f; switch(a_FixupType ) { diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index 7fc1db179a..e4fff11d32 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -484,6 +484,7 @@ namespace AZ } D3D12_RESOURCE_TRANSITION_BARRIER transition; + memset(&transition, 0, sizeof(D3D12_RESOURCE_TRANSITION_BARRIER)); // C4701 potentially unitialized local variable 'transition' used transition.pResource = image.GetMemoryView().GetMemory(); Scope& firstScope = static_cast(scopeAttachment->GetScope()); diff --git a/Gems/EMotionFX/Code/Tests/BoolLogicNodeTests.cpp b/Gems/EMotionFX/Code/Tests/BoolLogicNodeTests.cpp index 30950790d9..218bea2169 100644 --- a/Gems/EMotionFX/Code/Tests/BoolLogicNodeTests.cpp +++ b/Gems/EMotionFX/Code/Tests/BoolLogicNodeTests.cpp @@ -165,8 +165,8 @@ namespace EMotionFX const AZ::Outcome boolYParamIndexOutcome = m_animGraphInstance->FindParameterIndex(nameBoolY); success = boolXParamIndexOutcome.IsSuccess() && boolYParamIndexOutcome.IsSuccess(); - uint32 boolXOutputPortIndex; - uint32 boolYOutputPortIndex; + uint32 boolXOutputPortIndex = InvalidIndex32; + uint32 boolYOutputPortIndex = InvalidIndex32; const int portIndicesTosetCount = 2; int portIndicesFound = 0; const AZStd::vector& parameterNodeOutputPorts = parameterNode->GetOutputPorts(); diff --git a/Gems/FastNoise/Code/External/FastNoise/FastNoise.cpp b/Gems/FastNoise/Code/External/FastNoise/FastNoise.cpp index fce7d6498a..3fe7bf45fe 100644 --- a/Gems/FastNoise/Code/External/FastNoise/FastNoise.cpp +++ b/Gems/FastNoise/Code/External/FastNoise/FastNoise.cpp @@ -612,7 +612,9 @@ FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL int y1 = y0 + 1; int z1 = z0 + 1; - FN_DECIMAL xs, ys, zs; + FN_DECIMAL xs = 0.0f; + FN_DECIMAL ys = 0.0f; + FN_DECIMAL zs = 0.0f; switch (m_interp) { case Linear: @@ -726,7 +728,8 @@ FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL int x1 = x0 + 1; int y1 = y0 + 1; - FN_DECIMAL xs, ys; + FN_DECIMAL xs = 0.0f; + FN_DECIMAL ys = 0.0f; switch (m_interp) { case Linear: @@ -840,7 +843,9 @@ FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMA int y1 = y0 + 1; int z1 = z0 + 1; - FN_DECIMAL xs, ys, zs; + FN_DECIMAL xs = 0.0f; + FN_DECIMAL ys = 0.0f; + FN_DECIMAL zs = 0.0f; switch (m_interp) { case Linear: @@ -962,7 +967,8 @@ FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMA int x1 = x0 + 1; int y1 = y0 + 1; - FN_DECIMAL xs, ys; + FN_DECIMAL xs = 0.0f; + FN_DECIMAL ys = 0.0f; switch (m_interp) { case Linear: @@ -1699,7 +1705,9 @@ FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) c int zr = FastRound(z); FN_DECIMAL distance = 999999; - int xc, yc, zc; + int xc = 0; + int yc = 0; + int zc = 0; switch (m_cellularDistanceFunction) { @@ -1923,7 +1931,8 @@ FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y) const int yr = FastRound(y); FN_DECIMAL distance = 999999; - int xc, yc; + int xc = 0; + int yc = 0; switch (m_cellularDistanceFunction) { diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp index 28fb760c20..c2574a69f6 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp @@ -1239,7 +1239,7 @@ namespace GraphCanvas bool GraphUtils::IsValidModelConnection(const GraphId& graphId, const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint) { - bool validConnection; + bool validConnection = false; AZStd::unordered_set< Endpoint > finalSourceEndpoints = RemapEndpointForModel(sourceEndpoint); AZStd::unordered_set< Endpoint > finalTargetEndpoints = RemapEndpointForModel(targetEndpoint); diff --git a/Gems/LyShine/Code/Source/Animation/AzEntityNode.cpp b/Gems/LyShine/Code/Source/Animation/AzEntityNode.cpp index 7ff46f285f..2d24a84c71 100644 --- a/Gems/LyShine/Code/Source/Animation/AzEntityNode.cpp +++ b/Gems/LyShine/Code/Source/Animation/AzEntityNode.cpp @@ -691,7 +691,7 @@ IUiAnimTrack* CUiAnimAzEntityNode::CreateTrackForAzField(const UiAnimParamData& return nullptr; } - EUiAnimValue valueType; + EUiAnimValue valueType = eUiAnimValue_Unknown; switch (numElements) { case 2: diff --git a/Gems/LyShine/Code/Source/UiLayoutGridComponent.cpp b/Gems/LyShine/Code/Source/UiLayoutGridComponent.cpp index e39b9cc684..4c5d48911f 100644 --- a/Gems/LyShine/Code/Source/UiLayoutGridComponent.cpp +++ b/Gems/LyShine/Code/Source/UiLayoutGridComponent.cpp @@ -107,7 +107,8 @@ void UiLayoutGridComponent::ApplyLayoutHeight() AZStd::vector childEntityIds; EBUS_EVENT_ID_RESULT(childEntityIds, GetEntityId(), UiElementBus, GetChildEntityIds); int childIndex = 0; - int columnIndex, rowIndex; + int columnIndex = 0; + int rowIndex = 0; for (auto child : childEntityIds) { // Set the anchors @@ -627,7 +628,8 @@ AZ::Vector2 UiLayoutGridComponent::GetChildrenBoundingRectSize(const AZ::Vector2 UiLayoutHelpers::GetSizeInsidePadding(GetEntityId(), m_padding, layoutRectSize); // Calculate number of rows and columns - int numColumns, numRows; + int numColumns = 0; + int numRows = 0; switch (m_startingDirection) { case StartingDirection::HorizontalOrder: diff --git a/Gems/LyShine/Code/Source/UiNavigationHelpers.cpp b/Gems/LyShine/Code/Source/UiNavigationHelpers.cpp index 0c1b6765ce..79084c8bbe 100644 --- a/Gems/LyShine/Code/Source/UiNavigationHelpers.cpp +++ b/Gems/LyShine/Code/Source/UiNavigationHelpers.cpp @@ -151,6 +151,8 @@ namespace UiNavigationHelpers } UiTransformInterface::Rect parentRect; + parentRect.Set(0.0f, 0.0f, 0.0f, 0.0f); + AZ::Matrix4x4 parentTransformFromViewport; if (parentElement.IsValid() && !isCurElementDescendantOfParentElement) { diff --git a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp index abc2154228..1325638dd2 100644 --- a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp +++ b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp @@ -72,7 +72,7 @@ namespace NumericalMethods::Optimization for (AZ::u32 iteration = 0; iteration < lineSearchIterations; iteration++) { - ScalarVariable alphaNew; + ScalarVariable alphaNew = 0.0; if (iteration > 0) { // first try selecting a new alpha value based on cubic interpolation through the most recent points diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 25b6e63ab9..24dffe56a6 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -75,7 +75,6 @@ ly_append_configurations_options( /wd4450 # declaration hides global declaration /wd4457 # declaration hides function parameter /wd4459 # declaration hides global declaration - /wd4701 # potentially unintialized local variable # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From d56688e6cd9e620e384f8233431fa8180294da5a Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Thu, 3 Jun 2021 09:41:31 -0700 Subject: [PATCH 058/153] Adding a file that was missed when merging PR 481 from 1.0->main. Also, updated the comment a bit (#912) --- .../RPI/Code/Source/RPI.Public/Culling.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index c64f08e4f8..c5e9d949aa 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -239,16 +239,26 @@ namespace AZ void CullingScene::RegisterOrUpdateCullable(Cullable& cullable) { - m_cullDataConcurrencyCheck.soft_lock(); + // Multiple threads can call RegisterOrUpdateCullable at the same time + // since the underlying visScene is thread safe, but if you're inserting or + // updating between BeginCulling and EndCulling, you'll get non-deterministic + // results depending on a race condition if you happen to update before or after + // the culling system starts Enumerating, so use soft_lock_shared here + m_cullDataConcurrencyCheck.soft_lock_shared(); m_visScene->InsertOrUpdateEntry(cullable.m_cullData.m_visibilityEntry); - m_cullDataConcurrencyCheck.soft_unlock(); + m_cullDataConcurrencyCheck.soft_unlock_shared(); } void CullingScene::UnregisterCullable(Cullable& cullable) { - m_cullDataConcurrencyCheck.soft_lock(); + // Multiple threads can call RegisterOrUpdateCullable at the same time + // since the underlying visScene is thread safe, but if you're inserting or + // updating between BeginCulling and EndCulling, you'll get non-deterministic + // results depending on a race condition if you happen to update before or after + // the culling system starts Enumerating, so use soft_lock_shared here + m_cullDataConcurrencyCheck.soft_lock_shared(); m_visScene->RemoveEntry(cullable.m_cullData.m_visibilityEntry); - m_cullDataConcurrencyCheck.soft_unlock(); + m_cullDataConcurrencyCheck.soft_unlock_shared(); } uint32_t CullingScene::GetNumCullables() const From eef5122ce54dc44f97d852b4bf11b9a6a6cfc51b Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 3 Jun 2021 11:56:20 -0500 Subject: [PATCH 059/153] [LYN-3008] Only register the Slice Relationship View when prefabs are disabled. --- .../ComponentEntityEditorPlugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp index 54ac71db16..ed21b5b6e9 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp @@ -179,11 +179,11 @@ ComponentEntityEditorPlugin::ComponentEntityEditorPlugin([[maybe_unused]] IEdito LyViewPane::EntityOutliner, LyViewPane::CategoryTools, outlinerOptions); - } - AzToolsFramework::ViewPaneOptions options; - options.preferedDockingArea = Qt::NoDockWidgetArea; - RegisterViewPane(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options); + AzToolsFramework::ViewPaneOptions options; + options.preferedDockingArea = Qt::NoDockWidgetArea; + RegisterViewPane(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options); + } RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelectorHost()); From 5838975d626fc632d74f6069bfa329b5092ab062 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Thu, 3 Jun 2021 13:29:51 -0400 Subject: [PATCH 060/153] Incorporating review comments. Minor formatting changes and changes to parameter descriptions. Removed try-catch for property modification and added creation of user_tags element if it does not exist but is modified through CLI --- scripts/o3de/o3de/project_properties.py | 37 +++++++++++++------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 10153ff833..d8453a2c4f 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -21,22 +21,23 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display, new_summary, new_icon, new_tag) -> int: proj_json = get_project_props(proj_name, proj_path) - try: - if new_origin and 'origin' in proj_json: - proj_json['origin'] = new_origin - if new_display and 'display_name' in proj_json: - proj_json['display_name'] = new_display - if new_summary and 'summary' in proj_json: - proj_json['summary'] = new_summary - if new_icon and 'icon_path' in proj_json: - proj_json['icon_path'] = new_icon - if new_tag and 'user_tags' in proj_json: - proj_json['user_tags'].append(new_tag) - except Exception as e: - logger.error(e) + if not proj_json: return 1 - manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path)/'project.json') + if new_origin: + proj_json['origin'] = new_origin + if new_display: + proj_json['display_name'] = new_display + if new_summary: + proj_json['summary'] = new_summary + if new_icon: + proj_json['icon_path'] = new_icon + if new_tag: + if 'user_tags' not in proj_json: + proj_json['user_tags'] = [] + proj_json['user_tags'].append(new_tag) + + manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json') return 0 def _edit_project_props(args: argparse) -> int: @@ -56,7 +57,7 @@ def add_parser_args(parser): help='The name of the project.') group = parser.add_argument_group('properties', 'arguments for modifying individual project properties.') group.add_argument('-po', '--project-origin', type=str, required=False, - help='Sets description or url for project origin.') + help='Sets description or url for project origin (such as project host, repository, owner...etc).') group.add_argument('-pd', '--project-display', type=str, required=False, help='Sets the project display name.') group.add_argument('-ps', '--project-summary', type=str, required=False, @@ -64,11 +65,11 @@ def add_parser_args(parser): group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') group.add_argument('-pt', '--project-tag', type=str, required=False, - help='Adds a tag to canonical user tags.') + help='Adds a tag to canonical user tags. These tags are intended for documentation and filtering.') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: - enable_project_props_subparser = subparsers.add_parser('edit-project-props') + enable_project_props_subparser = subparsers.add_parser('edit-project-properties') add_parser_args(enable_project_props_subparser) def main(): @@ -79,4 +80,4 @@ def main(): sys.exit(ret) if __name__ == "__main__": - main() \ No newline at end of file + main() From c009e7d50bc47daa1a3a19c775d66c031c5b8a5f Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Thu, 3 Jun 2021 10:42:20 -0700 Subject: [PATCH 061/153] ATOM-4782 [Material] Transparent pass is using StandardPBR_Forwardpass shader with incorrect SRG (#1103) Removed TransparentPassSrg until we have pbr shaders TransparentPassSrg --- .../Materials/Special/ShadowCatcher.azsl | 2 +- .../Assets/Passes/TransparentParent.pass | 2 +- .../Atom/Features/PBR/ForwardPassSrg.azsli | 1 + .../Features/PBR/TransparentPassSrg.azsli | 39 ------------------- .../atom_feature_common_asset_files.cmake | 1 - 5 files changed, 3 insertions(+), 42 deletions(-) delete mode 100644 Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.azsl index 942db3ed5f..4a228f076c 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/ShadowCatcher.azsl @@ -37,7 +37,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial } #include -#include +#include #include #include diff --git a/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass index b278f2bcb4..a9db59c646 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass @@ -124,7 +124,7 @@ "DrawListSortType": "KeyThenReverseDepth", "PipelineViewTag": "MainCamera", "PassSrgAsset": { - "FilePath": "shaderlib/atom/features/pbr/transparentpasssrg.azsli:PassSrg" + "FilePath": "shaderlib/atom/features/pbr/forwardpasssrg.azsli:PassSrg" } } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassSrg.azsli index 14cff21739..d9367f9d03 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/ForwardPassSrg.azsli @@ -35,4 +35,5 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_tileLightData; StructuredBuffer m_lightListRemapped; + Texture2D m_linearDepthTexture; } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli deleted file mode 100644 index d9367f9d03..0000000000 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli +++ /dev/null @@ -1,39 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -#include - -ShaderResourceGroup PassSrg : SRG_PerPass -{ - // [GFX TODO][ATOM-2012] adapt to multiple shadowmaps - Texture2DArray m_directionalLightShadowmap; - Texture2DArray m_directionalLightExponentialShadowmap; - Texture2DArray m_projectedShadowmaps; - Texture2DArray m_projectedExponentialShadowmap; - Texture2D m_brdfMap; - - Sampler LinearSampler - { - MinFilter = Linear; - MagFilter = Linear; - MipFilter = Linear; - AddressU = Clamp; - AddressV = Clamp; - AddressW = Clamp; - }; - - Texture2D m_tileLightData; - StructuredBuffer m_lightListRemapped; - Texture2D m_linearDepthTexture; -} diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index 359c0b9b20..a9ba765329 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -246,7 +246,6 @@ set(FILES ShaderLib/Atom/Features/PBR/Hammersley.azsli ShaderLib/Atom/Features/PBR/LightingOptions.azsli ShaderLib/Atom/Features/PBR/LightingUtils.azsli - ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli ShaderLib/Atom/Features/PBR/Lighting/DualSpecularLighting.azsli ShaderLib/Atom/Features/PBR/Lighting/EnhancedLighting.azsli ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli From bcef8856ff2143fa137078525d98d47ddc6fe348 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 10:51:13 -0700 Subject: [PATCH 062/153] [cpack_installer] minor wording fixes --- cmake/Packaging.cmake | 2 +- scripts/build/Platform/Windows/installer_windows.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index e5799c8ff1..3e23511fa1 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -54,7 +54,7 @@ endif() if(${CPACK_DESIRED_CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_REQUIRED_VERSION}) message(FATAL_ERROR "The desired version of CMake to be included in the package is " - "is below the minimum required version of CMake to run") + "below the minimum required version of CMake to run") endif() # pull down the desired copy of CMake so it can be included in the package diff --git a/scripts/build/Platform/Windows/installer_windows.cmd b/scripts/build/Platform/Windows/installer_windows.cmd index c71b091de9..a6ce15d59e 100644 --- a/scripts/build/Platform/Windows/installer_windows.cmd +++ b/scripts/build/Platform/Windows/installer_windows.cmd @@ -20,7 +20,7 @@ IF NOT EXIST %OUTPUT_DIRECTORY% ( ) PUSHD %OUTPUT_DIRECTORY% -REM Override the temporary directory used by wix to the EBS volume +REM Override the temporary directory used by wix to the workspace SET "WIX_TEMP=!WORKSPACE!/temp/wix" IF NOT EXIST "%WIX_TEMP%" ( MKDIR "%WIX_TEMP%" From 8704b9233a699af223cfd0964bedd5271b79db45 Mon Sep 17 00:00:00 2001 From: mnaumov Date: Thu, 3 Jun 2021 10:53:00 -0700 Subject: [PATCH 063/153] build fix --- .../Rendering/ThumbnailRendererSteps/InitializeStep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp index c35c33017a..8bf157e5f3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include From 54fdca353b9d3a1108e4a5dd2f63a23b171cdb3a Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:54:14 -0500 Subject: [PATCH 064/153] Fix editor axis gizmo text rendering above gizmo Add AzToolsFramework utility function to query the display scale for a viewport. Use new function to fix the text location on the axis gizmo. --- .../ViewportSelection/EditorSelectionUtil.cpp | 11 +++++++++++ .../ViewportSelection/EditorSelectionUtil.h | 3 +++ .../EditorTransformComponentSelection.cpp | 7 ++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp index 88b92e8c41..d0143c5517 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp @@ -124,4 +124,15 @@ namespace AzToolsFramework return cameraState; } + + float GetScreenDisplayScaling(const int viewportId) + { + float scaling = 1.0f; + ViewportInteraction::ViewportInteractionRequestBus::EventResult( + scaling, viewportId, + &ViewportInteraction::ViewportInteractionRequestBus::Events::DeviceScalingFactor); + + return scaling; + } + } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h index 9936fb9afd..e904277078 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h @@ -60,6 +60,9 @@ namespace AzToolsFramework /// Wrapper for EBus call to return the CameraState for a given viewport. AzFramework::CameraState GetCameraState(int viewportId); + /// Wrapper for EBus call to return the DPI scaling for a given viewport. + float GetScreenDisplayScaling(const int viewportId); + /// A utility to return the center of several points. /// Take several positions and store the min and max of each in /// turn - when all points have been added return the center/midpoint. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 91ac495e0e..5acfa5df59 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -3573,9 +3573,10 @@ namespace AzToolsFramework debugDisplay.SetLineWidth(1.0f); const float labelOffset = cl_viewportGizmoAxisLabelOffset; - const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize; - const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize; - const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize; + const float screenScale = GetScreenDisplayScaling(viewportId); + const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize * screenScale; + const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize * screenScale; + const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize * screenScale; // draw the label of of each axis for the gizmo const float labelSize = cl_viewportGizmoAxisLabelSize; From 1bf8c599e3789999e2c33da5a2f82d77e48ea9df Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Thu, 27 May 2021 09:56:11 -0700 Subject: [PATCH 065/153] External Serialize Context for spawning This change makes it possible to provide a Serialize Context for spawning entities from spawnables. This also removes the need for the Serialize Context to be retrieved multiple times per frame. --- .../Spawnable/SpawnableEntitiesInterface.h | 54 +++++--- .../Spawnable/SpawnableEntitiesManager.cpp | 126 +++++++++--------- .../Spawnable/SpawnableEntitiesManager.h | 33 ++--- .../SpawnableEntitiesManagerTests.cpp | 24 +++- 4 files changed, 139 insertions(+), 98 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h index 27f45064b6..cfa1f3b464 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h @@ -21,6 +21,7 @@ namespace AZ { class Entity; + class SerializeContext; } namespace AzFramework @@ -171,6 +172,34 @@ namespace AzFramework using ClaimEntitiesCallback = AZStd::function; using BarrierCallback = AZStd::function; + struct SpawnEntitiesOptionalArgs + { + //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This + //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. + EntityPreInsertionCallback m_preInsertionCallback; + //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that + //! made the function call. The returned list of entities contains all the newly created entities. + EntitySpawnCallback m_completionCallback; + //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. + AZ::SerializeContext* m_serializeContext { nullptr }; + }; + + struct DespawnAllEntitiesOptionalArgs + { + //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that + //! made the function call. The returned list of entities contains all the newly created entities. + EntityDespawnCallback m_completionCallback; + }; + + struct ReloadSpawnableOptionalArgs + { + //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that + //! made the function call. The returned list of entities contains all the newly created entities. + ReloadSpawnableCallback m_completionCallback; + //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. + AZ::SerializeContext* m_serializeContext { nullptr }; + }; + //! Interface definition to (de)spawn entities from a spawnable into the game world. //! //! While the callbacks of the individual calls are being processed they will block processing any other request. Callbacks can be @@ -197,40 +226,31 @@ namespace AzFramework //! Spawn instances of all entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param priority The priority at which this call will be executed. - //! @param completionCallback Optional callback that's called when spawning entities has completed. This can be called from - //! a different thread than the one that made the function call. The returned list of entities contains all the newly - //! created entities. + //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void SpawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback = {}, - EntitySpawnCallback completionCallback = {}) = 0; + EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; //! Spawn instances of some entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param priority The priority at which this call will be executed. //! @param entityIndices The indices into the template entities stored in the spawnable that will be used to spawn entities from. - //! @param completionCallback Optional callback that's called when spawning entities has completed. This can be called from - //! a different thread than the one that made this function call. The returned list of entities contains all the newly - //! created entities. + //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void SpawnEntities( EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, - EntityPreInsertionCallback preInsertionCallback = {}, EntitySpawnCallback completionCallback = {}) = 0; + SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment. //! @param ticket The ticket previously used to spawn entities with. //! @param priority The priority at which this call will be executed. - //! @param completionCallback Optional callback that's called when despawning entities has completed. This can be called from - //! a different thread than the one that made this function call. + //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback = {}) = 0; - + EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment and reconstructs the entities from the provided spawnable. //! @param ticket Holds the information on the entities to reload. //! @param priority The priority at which this call will be executed. //! @param spawnable The spawnable that will replace the existing spawnable. Both need to have the same asset id. - //! @param completionCallback Optional callback that's called when the entities have been reloaded. This can be called from - //! a different thread than the one that made this function call. The returned list of entities contains all the replacement - //! entities. + //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void ReloadSpawnable( EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableCallback completionCallback = {}) = 0; + ReloadSpawnableOptionalArgs optionalArgs = {}) = 0; //! List all entities that are spawned using this ticket. //! @param ticket Only the entities associated with this ticket will be listed. diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp index 7b767d2a72..77106172f6 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp @@ -38,6 +38,10 @@ namespace AzFramework SpawnableEntitiesManager::SpawnableEntitiesManager() { + AZ::ComponentApplicationBus::BroadcastResult(m_defaultSerializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + AZ_Assert( + m_defaultSerializeContext, "Failed to retrieve serialization context during construction of the Spawnable Entities Manager."); + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { AZ::u64 value = aznumeric_caster(m_highPriorityThreshold); @@ -47,53 +51,57 @@ namespace AzFramework } void SpawnableEntitiesManager::SpawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback, - EntitySpawnCallback completionCallback) + EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnAllEntities hasn't been initialized."); SpawnAllEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); - queueEntry.m_completionCallback = AZStd::move(completionCallback); - queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback); + queueEntry.m_serializeContext = + optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; + queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); + queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback); QueueRequest(ticket, priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::SpawnEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, - EntityPreInsertionCallback preInsertionCallback, EntitySpawnCallback completionCallback) + EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnEntities hasn't been initialized."); SpawnEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_entityIndices = AZStd::move(entityIndices); - queueEntry.m_completionCallback = AZStd::move(completionCallback); - queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback); + queueEntry.m_serializeContext = + optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; + queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); + queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback); QueueRequest(ticket, priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback) + EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to DespawnAllEntities hasn't been initialized."); DespawnAllEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); - queueEntry.m_completionCallback = AZStd::move(completionCallback); + queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); QueueRequest(ticket, priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::ReloadSpawnable( EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableCallback completionCallback) + ReloadSpawnableOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to ReloadSpawnable hasn't been initialized."); ReloadSpawnableCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_spawnable = AZStd::move(spawnable); - queueEntry.m_completionCallback = AZStd::move(completionCallback); + queueEntry.m_serializeContext = + optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; + queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); QueueRequest(ticket, priority, AZStd::move(queueEntry)); } @@ -174,58 +182,57 @@ namespace AzFramework auto SpawnableEntitiesManager::ProcessQueue(Queue& queue) -> CommandQueueStatus { - AZStd::queue pendingRequestQueue; + // Process delayed requests first. + // Only process the requests that are currently in this queue, not the ones that could be re-added if they still can't complete. + size_t delayedSize = queue.m_delayed.size(); + for (size_t i = 0; i < delayedSize; ++i) { - AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex); - queue.m_pendingRequest.swap(pendingRequestQueue); + Requests& request = queue.m_delayed.front(); + bool result = AZStd::visit( + [this](auto&& args) -> bool + { + return ProcessRequest(args); + }, + request); + if (!result) + { + queue.m_delayed.emplace_back(AZStd::move(request)); + } + queue.m_delayed.pop_front(); } - if (!pendingRequestQueue.empty() || !queue.m_delayed.empty()) + // Process newly added requests. + while (true) { - AZ::SerializeContext* serializeContext = nullptr; - AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); - AZ_Assert(serializeContext, "Failed to retrieve serialization context."); - - // Only process the requests that are currently in this queue, not the ones that could be re-added if they still can't complete. - size_t delayedSize = queue.m_delayed.size(); - for (size_t i = 0; i < delayedSize; ++i) + AZStd::queue pendingRequestQueue; { - Requests& request = queue.m_delayed.front(); - bool result = AZStd::visit([this, serializeContext](auto&& args) -> bool - { - return ProcessRequest(args, *serializeContext); - }, request); - if (!result) - { - queue.m_delayed.emplace_back(AZStd::move(request)); - } - queue.m_delayed.pop_front(); + AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex); + queue.m_pendingRequest.swap(pendingRequestQueue); } - do + if (!pendingRequestQueue.empty()) { while (!pendingRequestQueue.empty()) { Requests& request = pendingRequestQueue.front(); - bool result = AZStd::visit([this, serializeContext](auto&& args) -> bool + bool result = AZStd::visit( + [this](auto&& args) -> bool { - return ProcessRequest(args, *serializeContext); - }, request); + return ProcessRequest(args); + }, + request); if (!result) { queue.m_delayed.emplace_back(AZStd::move(request)); } pendingRequestQueue.pop(); } - - // Spawning entities can result in more entities being queued to spawn. Repeat spawning until the queue is - // empty to avoid a chain of entity spawning getting dragged out over multiple frames. - { - AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex); - queue.m_pendingRequest.swap(pendingRequestQueue); - } - } while (!pendingRequestQueue.empty()); - } + } + else + { + break; + } + }; return queue.m_delayed.empty() ? CommandQueueStatus::NoCommandsLeft : CommandQueueStatus::HasCommandsLeft; } @@ -267,7 +274,7 @@ namespace AzFramework &entityTemplate, templateToCloneEntityIdMap, &serializeContext); } - bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (ticket.m_spawnable.IsReady() && request.m_requestId == ticket.m_currentRequestId) @@ -296,7 +303,7 @@ namespace AzFramework { const AZ::Entity& entityTemplate = *entitiesToSpawn[i]; - AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext); + AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, *request.m_serializeContext); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); @@ -347,7 +354,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(SpawnEntitiesCommand& request, AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(SpawnEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (ticket.m_spawnable.IsReady() && request.m_requestId == ticket.m_currentRequestId) @@ -371,7 +378,7 @@ namespace AzFramework { const AZ::Entity& entityTemplate = *entitiesToSpawn[index]; - AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate); + AZ::Entity* clone = request.m_serializeContext->CloneObject(&entityTemplate); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); clone->SetId(AZ::Entity::MakeId()); @@ -413,8 +420,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(DespawnAllEntitiesCommand& request, - [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(DespawnAllEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (request.m_requestId == ticket.m_currentRequestId) @@ -447,7 +453,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(ReloadSpawnableCommand& request, AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(ReloadSpawnableCommand& request) { Ticket& ticket = *request.m_ticket; AZ_Assert(ticket.m_spawnable.GetId() == request.m_spawnable.GetId(), @@ -488,7 +494,7 @@ namespace AzFramework { const AZ::Entity& entityTemplate = *entities[i]; - AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext); + AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, *request.m_serializeContext); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); @@ -502,7 +508,7 @@ namespace AzFramework for (size_t index : ticket.m_spawnedEntityIndices) { ticket.m_spawnedEntities.push_back( - index < entitiesSize ? SpawnSingleEntity(*entities[index], serializeContext) : nullptr); + index < entitiesSize ? SpawnSingleEntity(*entities[index], *request.m_serializeContext) : nullptr); } } ticket.m_spawnable = AZStd::move(request.m_spawnable); @@ -525,7 +531,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(ListEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(ListEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (request.m_requestId == ticket.m_currentRequestId) @@ -541,7 +547,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(ListIndicesEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(ListIndicesEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (request.m_requestId == ticket.m_currentRequestId) @@ -560,7 +566,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(ClaimEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(ClaimEntitiesCommand& request) { Ticket& ticket = *request.m_ticket; if (request.m_requestId == ticket.m_currentRequestId) @@ -580,7 +586,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(BarrierCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(BarrierCommand& request) { Ticket& ticket = *request.m_ticket; if (request.m_requestId == ticket.m_currentRequestId) @@ -599,7 +605,7 @@ namespace AzFramework } } - bool SpawnableEntitiesManager::ProcessRequest(DestroyTicketCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext) + bool SpawnableEntitiesManager::ProcessRequest(DestroyTicketCommand& request) { if (request.m_requestId == request.m_ticket->m_currentRequestId) { diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h index afffdab8b5..b40ec20aa3 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h @@ -57,19 +57,16 @@ namespace AzFramework // The following functions are thread safe // - void SpawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback = {}, - EntitySpawnCallback completionCallback = {}) override; + void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs = {}) override; void SpawnEntities( EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, - EntityPreInsertionCallback preInsertionCallback = {}, - EntitySpawnCallback completionCallback = {}) override; + SpawnEntitiesOptionalArgs optionalArgs = {}) override; void DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback = {}) override; + EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override; void ReloadSpawnable( EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableCallback completionCallback = {}) override; + ReloadSpawnableOptionalArgs optionalArgs = {}) override; void ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) override; void ListIndicesAndEntities( @@ -105,6 +102,7 @@ namespace AzFramework { EntitySpawnCallback m_completionCallback; EntityPreInsertionCallback m_preInsertionCallback; + AZ::SerializeContext* m_serializeContext; Ticket* m_ticket; EntitySpawnTicket::Id m_ticketId; uint32_t m_requestId; @@ -114,6 +112,7 @@ namespace AzFramework AZStd::vector m_entityIndices; EntitySpawnCallback m_completionCallback; EntityPreInsertionCallback m_preInsertionCallback; + AZ::SerializeContext* m_serializeContext; Ticket* m_ticket; EntitySpawnTicket::Id m_ticketId; uint32_t m_requestId; @@ -129,6 +128,7 @@ namespace AzFramework { AZ::Data::Asset m_spawnable; ReloadSpawnableCallback m_completionCallback; + AZ::SerializeContext* m_serializeContext; Ticket* m_ticket; EntitySpawnTicket::Id m_ticketId; uint32_t m_requestId; @@ -191,15 +191,15 @@ namespace AzFramework AZ::Entity* CloneSingleEntity(const AZ::Entity& entityTemplate, EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext); - bool ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(SpawnEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(DespawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(ReloadSpawnableCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(ListEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(ListIndicesEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(ClaimEntitiesCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(BarrierCommand& request, AZ::SerializeContext& serializeContext); - bool ProcessRequest(DestroyTicketCommand& request, AZ::SerializeContext& serializeContext); + bool ProcessRequest(SpawnAllEntitiesCommand& request); + bool ProcessRequest(SpawnEntitiesCommand& request); + bool ProcessRequest(DespawnAllEntitiesCommand& request); + bool ProcessRequest(ReloadSpawnableCommand& request); + bool ProcessRequest(ListEntitiesCommand& request); + bool ProcessRequest(ListIndicesEntitiesCommand& request); + bool ProcessRequest(ClaimEntitiesCommand& request); + bool ProcessRequest(BarrierCommand& request); + bool ProcessRequest(DestroyTicketCommand& request); Queue m_highPriorityQueue; Queue m_regularPriorityQueue; @@ -207,6 +207,7 @@ namespace AzFramework AZ::Event> m_onSpawnedEvent; AZ::Event> m_onDespawnedEvent; + AZ::SerializeContext* m_defaultSerializeContext { nullptr }; //! The threshold used to determine if a request goes in the regular (if bigger than the value) or high priority queue (if smaller //! or equal to this value). The starting value of 64 is chosen as it's between default values SpawnablePriority_High and //! SpawnablePriority_Default which gives users a bit of room to fine tune the priorities as this value can be configured diff --git a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 484b7f46d7..7a2e7f614b 100644 --- a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -104,7 +104,9 @@ namespace UnitTest { spawnedEntitiesCount += entities.size(); }; - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, {}, AZStd::move(callback)); + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); EXPECT_EQ(NumEntities, spawnedEntitiesCount); @@ -305,8 +307,14 @@ namespace UnitTest defaultPriorityCallId = callCounter++; }; - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, {}, AZStd::move(defaultCallback)); - m_manager->SpawnAllEntities(highPriorityTicket, AzFramework::SpawnablePriority_High, {}, AZStd::move(highCallback)); + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(defaultCallback); + m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); + + AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; + highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); + m_manager->SpawnAllEntities(highPriorityTicket, AzFramework::SpawnablePriority_High, AZStd::move(highPriortyOptionalArgs)); + m_manager->ProcessQueue( AzFramework::SpawnableEntitiesManager::CommandQueuePriority::High | AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); @@ -333,8 +341,14 @@ namespace UnitTest defaultPriorityCallId = callCounter++; }; - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, {}, AZStd::move(defaultCallback)); - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_High, {}, AZStd::move(highCallback)); + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(defaultCallback); + m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); + + AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; + highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); + m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_High, AZStd::move(highPriortyOptionalArgs)); + m_manager->ProcessQueue( AzFramework::SpawnableEntitiesManager::CommandQueuePriority::High | AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); From 8c541b5205dd7605965e9719df6bfcfc1470f52a Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Tue, 1 Jun 2021 16:11:55 -0700 Subject: [PATCH 066/153] Moved default values to object in the Spawnable Entities Interface --- .../Spawnable/SpawnableEntitiesContainer.cpp | 11 ++-- .../Spawnable/SpawnableEntitiesInterface.h | 53 +++++++++++++------ .../Spawnable/SpawnableEntitiesManager.cpp | 37 +++++++------ .../Spawnable/SpawnableEntitiesManager.h | 22 ++++---- .../SpawnableEntitiesManagerTests.cpp | 26 +++++---- .../Libraries/Spawning/SpawnNodeable.cpp | 6 ++- 6 files changed, 88 insertions(+), 67 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesContainer.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesContainer.cpp index 808de74e71..a945ea4edc 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesContainer.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesContainer.cpp @@ -38,20 +38,20 @@ namespace AzFramework void SpawnableEntitiesContainer::SpawnAllEntities() { AZ_Assert(m_threadData, "Calling SpawnAllEntities on a Spawnable container that's not set."); - SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default); + SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_threadData->m_spawnedEntitiesTicket); } void SpawnableEntitiesContainer::SpawnEntities(AZStd::vector entityIndices) { AZ_Assert(m_threadData, "Calling SpawnEntities on a Spawnable container that's not set."); SpawnableEntitiesInterface::Get()->SpawnEntities( - m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default, AZStd::move(entityIndices)); + m_threadData->m_spawnedEntitiesTicket, AZStd::move(entityIndices)); } void SpawnableEntitiesContainer::DespawnAllEntities() { AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set."); - SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default); + SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_threadData->m_spawnedEntitiesTicket); } void SpawnableEntitiesContainer::Reset(AZ::Data::Asset spawnable) @@ -69,7 +69,6 @@ namespace AzFramework SpawnableEntitiesInterface::Get()->Barrier( m_threadData->m_spawnedEntitiesTicket, - SpawnablePriority_Default, [threadData = m_threadData](EntitySpawnTicket::Id) mutable { threadData.reset(); @@ -88,7 +87,6 @@ namespace AzFramework AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set."); SpawnableEntitiesInterface::Get()->Barrier( m_threadData->m_spawnedEntitiesTicket, - SpawnablePriority_Default, [generation = m_threadData->m_generation, callback = AZStd::move(callback)](EntitySpawnTicket::Id) { callback(generation); @@ -115,7 +113,6 @@ namespace AzFramework AZ_Assert(m_threadData, "SpawnableEntitiesContainer is monitoring a spawnable, but doesn't have the associated data."); AZ_TracePrintf("Spawnables", "Reloading spawnable '%s'.\n", replacementAsset.GetHint().c_str()); - SpawnableEntitiesInterface::Get()->ReloadSpawnable( - m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default, AZStd::move(replacementAsset)); + SpawnableEntitiesInterface::Get()->ReloadSpawnable(m_threadData->m_spawnedEntitiesTicket, AZStd::move(replacementAsset)); } } // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h index cfa1f3b464..5d7ce79641 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h @@ -172,7 +172,7 @@ namespace AzFramework using ClaimEntitiesCallback = AZStd::function; using BarrierCallback = AZStd::function; - struct SpawnEntitiesOptionalArgs + struct SpawnEntitiesOptionalArgs final { //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. @@ -182,22 +182,46 @@ namespace AzFramework EntitySpawnCallback m_completionCallback; //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. AZ::SerializeContext* m_serializeContext { nullptr }; + //! The priority at which this call will be executed. + SpawnablePriority m_priority { SpawnablePriority_Default }; }; - struct DespawnAllEntitiesOptionalArgs + struct DespawnAllEntitiesOptionalArgs final { //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that //! made the function call. The returned list of entities contains all the newly created entities. EntityDespawnCallback m_completionCallback; + //! The priority at which this call will be executed. + SpawnablePriority m_priority { SpawnablePriority_Default }; }; - struct ReloadSpawnableOptionalArgs + struct ReloadSpawnableOptionalArgs final { //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that //! made the function call. The returned list of entities contains all the newly created entities. ReloadSpawnableCallback m_completionCallback; //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. AZ::SerializeContext* m_serializeContext { nullptr }; + //! The priority at which this call will be executed. + SpawnablePriority m_priority { SpawnablePriority_Default }; + }; + + struct ListEntitiesOptionalArgs final + { + //! The priority at which this call will be executed. + SpawnablePriority m_priority{ SpawnablePriority_Default }; + }; + + struct ClaimEntitiesOptionalArgs final + { + //! The priority at which this call will be executed. + SpawnablePriority m_priority{ SpawnablePriority_Default }; + }; + + struct BarrierOptionalArgs final + { + //! The priority at which this call will be executed. + SpawnablePriority m_priority{ SpawnablePriority_Default }; }; //! Interface definition to (de)spawn entities from a spawnable into the game world. @@ -225,38 +249,34 @@ namespace AzFramework //! Spawn instances of all entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. - //! @param priority The priority at which this call will be executed. //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs - virtual void SpawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; + virtual void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; //! Spawn instances of some entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param priority The priority at which this call will be executed. //! @param entityIndices The indices into the template entities stored in the spawnable that will be used to spawn entities from. //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void SpawnEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, - SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; + EntitySpawnTicket& ticket, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment. //! @param ticket The ticket previously used to spawn entities with. //! @param priority The priority at which this call will be executed. //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs - virtual void DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; + virtual void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment and reconstructs the entities from the provided spawnable. //! @param ticket Holds the information on the entities to reload. //! @param priority The priority at which this call will be executed. //! @param spawnable The spawnable that will replace the existing spawnable. Both need to have the same asset id. //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs virtual void ReloadSpawnable( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableOptionalArgs optionalArgs = {}) = 0; + EntitySpawnTicket& ticket, AZ::Data::Asset spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) = 0; //! List all entities that are spawned using this ticket. //! @param ticket Only the entities associated with this ticket will be listed. //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to list the entities on. - virtual void ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) = 0; + virtual void ListEntities( + EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0; //! List all entities that are spawned using this ticket with their spawnable index. //! Spawnables contain a flat list of entities, which are used as templates to spawn entities from. For every spawned entity //! the index of the entity in the spawnable that was used as a template is stored. This version of ListEntities will return @@ -267,20 +287,21 @@ namespace AzFramework //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to list the entities and indices on. virtual void ListIndicesAndEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback) = 0; + EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0; //! Claim all entities that are spawned using this ticket. Ownership of the entities is transferred from the ticket to the //! caller through the callback. After this call the ticket will have no entities associated with it. The caller of //! this function will need to manage the entities after this call. //! @param ticket Only the entities associated with this ticket will be released. //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to transfer the entities through. - virtual void ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback) = 0; + virtual void ClaimEntities( + EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs = {}) = 0; //! Blocks until all operations made on the provided ticket before the barrier call have completed. //! @param ticket The ticket to monitor. //! @param priority The priority at which this call will be executed. //! @param completionCallback Required callback that will be called as soon as the barrier has been reached. - virtual void Barrier(EntitySpawnTicket& ticket, SpawnablePriority priority, BarrierCallback completionCallback) = 0; + virtual void Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) = 0; //! Register a handler for OnSpawned events. virtual void AddOnSpawnedHandler(AZ::Event>::Handler& handler) = 0; diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp index 77106172f6..c11ce94bb2 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp @@ -50,8 +50,7 @@ namespace AzFramework } } - void SpawnableEntitiesManager::SpawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs) + void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnAllEntities hasn't been initialized."); @@ -61,11 +60,11 @@ namespace AzFramework optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::SpawnEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs) + EntitySpawnTicket& ticket, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnEntities hasn't been initialized."); @@ -76,23 +75,21 @@ namespace AzFramework optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } - void SpawnableEntitiesManager::DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs) + void SpawnableEntitiesManager::DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to DespawnAllEntities hasn't been initialized."); DespawnAllEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::ReloadSpawnable( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableOptionalArgs optionalArgs) + EntitySpawnTicket& ticket, AZ::Data::Asset spawnable, ReloadSpawnableOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to ReloadSpawnable hasn't been initialized."); @@ -102,10 +99,11 @@ namespace AzFramework queueEntry.m_serializeContext = optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } - void SpawnableEntitiesManager::ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) + void SpawnableEntitiesManager::ListEntities( + EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs) { AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use."); AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized."); @@ -113,11 +111,11 @@ namespace AzFramework ListEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_listCallback = AZStd::move(listCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::ListIndicesAndEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback) + EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs) { AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use."); AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized."); @@ -125,10 +123,11 @@ namespace AzFramework ListIndicesEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_listCallback = AZStd::move(listCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } - void SpawnableEntitiesManager::ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback) + void SpawnableEntitiesManager::ClaimEntities( + EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs) { AZ_Assert(listCallback, "ClaimEntities called on spawnable entities without a valid callback to use."); AZ_Assert(ticket.IsValid(), "Ticket provided to ClaimEntities hasn't been initialized."); @@ -136,10 +135,10 @@ namespace AzFramework ClaimEntitiesCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_listCallback = AZStd::move(listCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } - void SpawnableEntitiesManager::Barrier(EntitySpawnTicket& ticket, SpawnablePriority priority, BarrierCallback completionCallback) + void SpawnableEntitiesManager::Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs) { AZ_Assert(completionCallback, "Barrier on spawnable entities called without a valid callback to use."); AZ_Assert(ticket.IsValid(), "Ticket provided to Barrier hasn't been initialized."); @@ -147,7 +146,7 @@ namespace AzFramework BarrierCommand queueEntry; queueEntry.m_ticketId = ticket.GetId(); queueEntry.m_completionCallback = AZStd::move(completionCallback); - QueueRequest(ticket, priority, AZStd::move(queueEntry)); + QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } void SpawnableEntitiesManager::AddOnSpawnedHandler(AZ::Event>::Handler& handler) diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h index b40ec20aa3..e6db19557f 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h @@ -57,23 +57,21 @@ namespace AzFramework // The following functions are thread safe // - void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, SpawnEntitiesOptionalArgs optionalArgs = {}) override; + void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs = {}) override; void SpawnEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector entityIndices, - SpawnEntitiesOptionalArgs optionalArgs = {}) override; - void DespawnAllEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override; - + EntitySpawnTicket& ticket, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) override; + void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override; void ReloadSpawnable( - EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset spawnable, - ReloadSpawnableOptionalArgs optionalArgs = {}) override; + EntitySpawnTicket& ticket, AZ::Data::Asset spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) override; - void ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) override; + void ListEntities( + EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) override; void ListIndicesAndEntities( - EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback) override; - void ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback) override; + EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) override; + void ClaimEntities( + EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs = {}) override; - void Barrier(EntitySpawnTicket& spawnInfo, SpawnablePriority priority, BarrierCallback completionCallback) override; + void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) override; void AddOnSpawnedHandler(AZ::Event>::Handler& handler) override; void AddOnDespawnedHandler(AZ::Event>::Handler& handler) override; diff --git a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 7a2e7f614b..8637684b3c 100644 --- a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -106,7 +106,7 @@ namespace UnitTest }; AzFramework::SpawnEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(callback); - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); + m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); EXPECT_EQ(NumEntities, spawnedEntitiesCount); @@ -116,7 +116,7 @@ namespace UnitTest { { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->SpawnAllEntities(ticket, AzFramework::SpawnablePriority_Default); + m_manager->SpawnAllEntities(ticket); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -130,7 +130,7 @@ namespace UnitTest { { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->SpawnEntities(ticket, AzFramework::SpawnablePriority_Default, {}); + m_manager->SpawnEntities(ticket, {/* Deliberate empty list of indices. */}); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -144,7 +144,7 @@ namespace UnitTest { { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->DespawnAllEntities(ticket, AzFramework::SpawnablePriority_Default); + m_manager->DespawnAllEntities(ticket); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -158,7 +158,7 @@ namespace UnitTest { { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->ReloadSpawnable(ticket, AzFramework::SpawnablePriority_Default, *m_spawnableAsset); + m_manager->ReloadSpawnable(ticket, *m_spawnableAsset); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -185,7 +185,7 @@ namespace UnitTest spawnedEntitiesCount += entities.size(); }; - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default); + m_manager->SpawnAllEntities(*m_ticket); m_manager->ListEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); @@ -230,7 +230,7 @@ namespace UnitTest } }; - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default); + m_manager->SpawnAllEntities(*m_ticket); m_manager->ListIndicesAndEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); @@ -309,11 +309,13 @@ namespace UnitTest AzFramework::SpawnEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(defaultCallback); - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); + optionalArgs.m_priority = AzFramework::SpawnablePriority_Default; + m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); - m_manager->SpawnAllEntities(highPriorityTicket, AzFramework::SpawnablePriority_High, AZStd::move(highPriortyOptionalArgs)); + highPriortyOptionalArgs.m_priority = AzFramework::SpawnablePriority_High; + m_manager->SpawnAllEntities(highPriorityTicket, AZStd::move(highPriortyOptionalArgs)); m_manager->ProcessQueue( AzFramework::SpawnableEntitiesManager::CommandQueuePriority::High | @@ -343,11 +345,13 @@ namespace UnitTest AzFramework::SpawnEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(defaultCallback); - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(optionalArgs)); + optionalArgs.m_priority = AzFramework::SpawnablePriority_Default; + m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); - m_manager->SpawnAllEntities(*m_ticket, AzFramework::SpawnablePriority_High, AZStd::move(highPriortyOptionalArgs)); + highPriortyOptionalArgs.m_priority = AzFramework::SpawnablePriority_High; + m_manager->SpawnAllEntities(*m_ticket, AZStd::move(highPriortyOptionalArgs)); m_manager->ProcessQueue( AzFramework::SpawnableEntitiesManager::CommandQueuePriority::High | diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp index ad53236108..39afa46a19 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp @@ -134,7 +134,9 @@ namespace ScriptCanvas::Nodeables::Spawning m_spawnBatchSizes.push_back(view.size()); }; - AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities( - m_spawnTicket, AzFramework::SpawnablePriority_Default, preSpawnCB, spawnCompleteCB); + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_preInsertionCallback = AZStd::move(preSpawnCB); + optionalArgs.m_completionCallback = AZStd::move(spawnCompleteCB); + AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_spawnTicket, AZStd::move(optionalArgs)); } } From 1e7ac6094982b78a262da2989507fcbf0ab0d566 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Thu, 3 Jun 2021 10:49:25 -0700 Subject: [PATCH 067/153] Reintroduced spawning multiple instances of the same entity The following was changed: - The remapper in AZ::IdUtils now has an additional argument to tell it what to do when it encounters the same source entity id. The original behavior of ignoring the new entity id and returning the first occurrence is the default. The alternative behavior is to store the last known entity id and return that instead. - Split the optional arguments for SpawnAllEntities and SpawnEntities. - SpawnEntities now has an option to continue with the entity mapping from a previous spawn call or to start with a fresh mapping. The latter is the default as the former will come at a performance cost since the mapping table has to be reconstructed. - Entities spawned using SpawnEntities and ReloadEntities now also get the correct entity mapping applied. - Added several new unit tests to cover most of the new functionality. - Fixed some places where the older API version was still called. --- .../AzCore/AzCore/Serialization/IdUtils.h | 28 +- .../AzCore/AzCore/Serialization/IdUtils.inl | 16 +- .../Spawnable/SpawnableEntitiesInterface.h | 23 +- .../Spawnable/SpawnableEntitiesManager.cpp | 111 ++++---- .../Spawnable/SpawnableEntitiesManager.h | 14 +- .../SpawnableEntitiesManagerTests.cpp | 254 +++++++++++++++++- .../Pipeline/NetBindMarkerComponent.cpp | 6 +- .../Libraries/Spawning/SpawnNodeable.cpp | 2 +- 8 files changed, 362 insertions(+), 92 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h index a571379883..98959fe4bd 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h +++ b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h @@ -28,7 +28,13 @@ namespace AZ { namespace IdUtils { - template + /** + * \param AllowDuplicates - If true allows the same id to be registered multiple time, + with the newer value overwriting the stored value. If false, duplicates are not allowed and + the first stored value is kept.The default is false. + */ + + template struct Remapper { /** @@ -138,14 +144,18 @@ namespace AZ * \param context - The serialize context for enumerating the @classPtr elements */ template - static void GenerateNewIdsAndFixRefs(T* object, MapType& newIdMap, AZ::SerializeContext* context = nullptr) + static void GenerateNewIdsAndFixRefs( + T* object, MapType& newIdMap, AZ::SerializeContext* context = nullptr) { if (!context) { AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext); if (!context) { - AZ_Error("Serialization", false, "No serialize context provided! Failed to get component application default serialize context! ComponentApp is not started or input serialize context should not be null!"); + AZ_Error( + "Serialization", false, + "No serialize context provided! Failed to get component application default serialize context! ComponentApp is " + "not started or input serialize context should not be null!"); return; } } @@ -156,8 +166,16 @@ namespace AZ { if (idGenerator) { - auto it = newIdMap.emplace(originalId, idGenerator()); - return it.first->second; + if constexpr(AllowDuplicates) + { + auto it = newIdMap.insert_or_assign(originalId, idGenerator()); + return it.first->second; + } + else + { + auto it = newIdMap.emplace(originalId, idGenerator()); + return it.first->second; + } } return originalId; } diff --git a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.inl b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.inl index 01617cf5aa..0dc87dfe18 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.inl @@ -30,8 +30,10 @@ namespace AZ bool m_isModifiedContainer; }; - template - unsigned int Remapper::RemapIds(void* classPtr, const AZ::Uuid& classUuid, const typename Remapper::IdMapper& mapper, AZ::SerializeContext* context, bool replaceId) + template + unsigned int Remapper::RemapIds( + void* classPtr, const AZ::Uuid& classUuid, const typename Remapper::IdMapper& mapper, + AZ::SerializeContext* context, bool replaceId) { if (!context) { @@ -152,16 +154,18 @@ namespace AZ return replaced; } - template - unsigned int Remapper::ReplaceIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const IdMapper& mapper, AZ::SerializeContext* context /*= nullptr*/) + template + unsigned int Remapper::ReplaceIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const IdMapper& mapper, AZ::SerializeContext* context /*= nullptr*/) { unsigned int replaced = RemapIds(classPtr, classUuid, mapper, context, true); replaced += RemapIds(classPtr, classUuid, mapper, context, false); return replaced; } - template - unsigned int Remapper::RemapIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const typename Remapper::IdReplacer& mapper, AZ::SerializeContext* context) + template + unsigned int Remapper::RemapIdsAndIdRefs( + void* classPtr, const AZ::Uuid& classUuid, const typename Remapper::IdReplacer& mapper, + AZ::SerializeContext* context) { if (!context) { diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h index 5d7ce79641..2ad1db60a4 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h @@ -172,7 +172,7 @@ namespace AzFramework using ClaimEntitiesCallback = AZStd::function; using BarrierCallback = AZStd::function; - struct SpawnEntitiesOptionalArgs final + struct SpawnAllEntitiesOptionalArgs final { //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. @@ -186,6 +186,25 @@ namespace AzFramework SpawnablePriority m_priority { SpawnablePriority_Default }; }; + struct SpawnEntitiesOptionalArgs final + { + //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This + //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. + EntityPreInsertionCallback m_preInsertionCallback; + //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that + //! made the function call. The returned list of entities contains all the newly created entities. + EntitySpawnCallback m_completionCallback; + //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. + AZ::SerializeContext* m_serializeContext{ nullptr }; + //! The priority at which this call will be executed. + SpawnablePriority m_priority{ SpawnablePriority_Default }; + //! Entity references are resolved by referring to the last entity spawned from a template entity in the spawnable. If this + //! is set to false entities from previous spawn calls are not taken into account. If set to true entity references may be + //! resolved to a previously spawned entity. A lookup table has to be constructed when true, which may negatively impact + //! performance, especially if a large number of entities are present on a ticket. + bool m_referencePreviouslySpawnedEntities{ false }; + }; + struct DespawnAllEntitiesOptionalArgs final { //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that @@ -250,7 +269,7 @@ namespace AzFramework //! Spawn instances of all entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs - virtual void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; + virtual void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; //! Spawn instances of some entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param priority The priority at which this call will be executed. diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp index c11ce94bb2..a482c1d4f9 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.cpp @@ -50,7 +50,7 @@ namespace AzFramework } } - void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs) + void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs) { AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnAllEntities hasn't been initialized."); @@ -75,6 +75,7 @@ namespace AzFramework optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext; queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback); queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback); + queueEntry.m_referencePreviouslySpawnedEntities = optionalArgs.m_referencePreviouslySpawnedEntities; QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry)); } @@ -256,21 +257,11 @@ namespace AzFramework } } - AZ::Entity* SpawnableEntitiesManager::SpawnSingleEntity(const AZ::Entity& entityTemplate, AZ::SerializeContext& serializeContext) - { - AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate); - AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); - clone->SetId(AZ::Entity::MakeId()); - - GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, clone); - return clone; - } - AZ::Entity* SpawnableEntitiesManager::CloneSingleEntity(const AZ::Entity& entityTemplate, - EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext) + EntityIdMap& templateToCloneMap, AZ::SerializeContext& serializeContext) { - return AZ::IdUtils::Remapper::CloneObjectAndGenerateNewIdsAndFixRefs( - &entityTemplate, templateToCloneEntityIdMap, &serializeContext); + return AZ::IdUtils::Remapper::CloneObjectAndGenerateNewIdsAndFixRefs( + &entityTemplate, templateToCloneMap, &serializeContext); } bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request) @@ -297,13 +288,9 @@ namespace AzFramework spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize); templateToCloneEntityIdMap.reserve(entitiesToSpawnSize); - // Mark all indices as spawned for (size_t i = 0; i < entitiesToSpawnSize; ++i) { - const AZ::Entity& entityTemplate = *entitiesToSpawn[i]; - - AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, *request.m_serializeContext); - + AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[i], templateToCloneEntityIdMap, *request.m_serializeContext); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); spawnedEntities.emplace_back(clone); @@ -311,16 +298,8 @@ namespace AzFramework } // loadAll is true if every entity has been spawned only once - if (spawnedEntities.size() == entitiesToSpawnSize) - { - ticket.m_loadAll = true; - } - else - { - // Case where there were already spawns from a previous request - ticket.m_loadAll = false; - } - + ticket.m_loadAll = (spawnedEntities.size() == entitiesToSpawnSize); + // Let other systems know about newly spawned entities for any pre-processing before adding to the scene/game context. if (request.m_preInsertionCallback) { @@ -329,11 +308,10 @@ namespace AzFramework } // Add to the game context, now the entities are active - AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(), - [](AZ::Entity* entity) + for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it) { - GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity); - }); + GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it); + } // Let other systems know about newly spawned entities for any post-processing after adding to the scene/game context. if (request.m_completionCallback) @@ -360,14 +338,34 @@ namespace AzFramework { AZStd::vector& spawnedEntities = ticket.m_spawnedEntities; AZStd::vector& spawnedEntityIndices = ticket.m_spawnedEntityIndices; + AZ_Assert( + spawnedEntities.size() == spawnedEntityIndices.size(), + "The indices for the spawned entities has gone out of sync with the entities."); - // Keep track how many entities there were in the array initially + // Keep track of how many entities there were in the array initially size_t spawnedEntitiesInitialCount = spawnedEntities.size(); // These are 'template' entities we'll be cloning from const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities(); size_t entitiesToSpawnSize = request.m_entityIndices.size(); + // Reconstruct the template to entity mapping. + EntityIdMap templateToCloneEntityIdMap; + if (!request.m_referencePreviouslySpawnedEntities) + { + templateToCloneEntityIdMap.reserve(entitiesToSpawnSize); + } + else + { + templateToCloneEntityIdMap.reserve(spawnedEntitiesInitialCount + entitiesToSpawnSize); + SpawnableConstIndexEntityContainerView indexEntityView( + spawnedEntities.begin(), spawnedEntityIndices.begin(), spawnedEntities.size()); + for (auto& entry : indexEntityView) + { + templateToCloneEntityIdMap.insert_or_assign(entitiesToSpawn[entry.GetIndex()]->GetId(), entry.GetEntity()->GetId()); + } + } + spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize); spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize); @@ -375,15 +373,11 @@ namespace AzFramework { if (index < entitiesToSpawn.size()) { - const AZ::Entity& entityTemplate = *entitiesToSpawn[index]; - - AZ::Entity* clone = request.m_serializeContext->CloneObject(&entityTemplate); + AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[index], templateToCloneEntityIdMap, *request.m_serializeContext); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); - clone->SetId(AZ::Entity::MakeId()); spawnedEntities.push_back(clone); spawnedEntityIndices.push_back(index); - } } ticket.m_loadAll = false; @@ -396,11 +390,10 @@ namespace AzFramework } // Add to the game context, now the entities are active - AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(), - [](AZ::Entity* entity) + for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it) { - GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity); - }); + GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it); + } if (request.m_completionCallback) { @@ -475,39 +468,43 @@ namespace AzFramework // Rebuild the list of entities. ticket.m_spawnedEntities.clear(); const Spawnable::EntityList& entities = request.m_spawnable->GetEntities(); + + // Map keeps track of ids from template (spawnable) to clone (instance) + // Allowing patch ups of fields referring to entityIds outside of a given entity + EntityIdMap templateToCloneEntityIdMap; + if (ticket.m_loadAll) { // The new spawnable may have a different number of entities and since the intent of the user was - // to load every, simply start over. + // to spawn every entity, simply start over. ticket.m_spawnedEntityIndices.clear(); - size_t entitiesToSpawnSize = entities.size(); - - // Map keeps track of ids from template (spawnable) to clone (instance) - // Allowing patch ups of fields referring to entityIds outside of a given entity - EntityIdMap templateToCloneEntityIdMap; templateToCloneEntityIdMap.reserve(entitiesToSpawnSize); - // Mark all indices as spawned for (size_t i = 0; i < entitiesToSpawnSize; ++i) { - const AZ::Entity& entityTemplate = *entities[i]; - - AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, *request.m_serializeContext); - + AZ::Entity* clone = CloneSingleEntity(*entities[i], templateToCloneEntityIdMap, *request.m_serializeContext); AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); - ticket.m_spawnedEntities.emplace_back(clone); + ticket.m_spawnedEntities.push_back(clone); ticket.m_spawnedEntityIndices.push_back(i); } } else { size_t entitiesSize = entities.size(); + templateToCloneEntityIdMap.reserve(entitiesSize); for (size_t index : ticket.m_spawnedEntityIndices) { - ticket.m_spawnedEntities.push_back( - index < entitiesSize ? SpawnSingleEntity(*entities[index], *request.m_serializeContext) : nullptr); + // It's possible for the new spawnable to have a different number of entities, so guard against this. + // It's also possible that the entities have moved within the spawnable to a new index. This can't be + // detected and will result in the incorrect entities being spawned. + if (index < entitiesSize) + { + AZ::Entity* clone = CloneSingleEntity(*entities[index], templateToCloneEntityIdMap, *request.m_serializeContext); + AZ_Assert(clone != nullptr, "Failed to clone spawnable entity."); + ticket.m_spawnedEntities.push_back(clone); + } } } ticket.m_spawnable = AZStd::move(request.m_spawnable); diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h index e6db19557f..638559f3f1 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesManager.h @@ -37,7 +37,7 @@ namespace AzFramework AZ_CLASS_ALLOCATOR(SpawnableEntitiesManager, AZ::SystemAllocator, 0); using EntityIdMap = AZStd::unordered_map; - + enum class CommandQueueStatus : bool { HasCommandsLeft, @@ -57,7 +57,7 @@ namespace AzFramework // The following functions are thread safe // - void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnEntitiesOptionalArgs optionalArgs = {}) override; + void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs = {}) override; void SpawnEntities( EntitySpawnTicket& ticket, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) override; void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override; @@ -114,6 +114,7 @@ namespace AzFramework Ticket* m_ticket; EntitySpawnTicket::Id m_ticketId; uint32_t m_requestId; + bool m_referencePreviouslySpawnedEntities; }; struct DespawnAllEntitiesCommand { @@ -183,12 +184,9 @@ namespace AzFramework CommandQueueStatus ProcessQueue(Queue& queue); - AZ::Entity* SpawnSingleEntity(const AZ::Entity& entityTemplate, - AZ::SerializeContext& serializeContext); - - AZ::Entity* CloneSingleEntity(const AZ::Entity& entityTemplate, - EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext); - + AZ::Entity* CloneSingleEntity( + const AZ::Entity& entityTemplate, EntityIdMap& templateToCloneMap, AZ::SerializeContext& serializeContext); + bool ProcessRequest(SpawnAllEntitiesCommand& request); bool ProcessRequest(SpawnEntitiesCommand& request); bool ProcessRequest(DespawnAllEntitiesCommand& request); diff --git a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 8637684b3c..32ad7d8ea9 100644 --- a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace UnitTest @@ -81,6 +82,42 @@ namespace UnitTest } } + void CreateRecursiveHierarchy() + { + AzFramework::Spawnable::EntityList& entities = m_spawnable->GetEntities(); + size_t numElements = entities.size(); + AZ::EntityId parent; + for (size_t i=0; i& entity = entities[i]; + auto component = entity->CreateComponent(); + if (i > 0) + { + component->SetParent(parent); + } + parent = entity->GetId(); + } + } + + void CreateSingleParent() + { + AzFramework::Spawnable::EntityList& entities = m_spawnable->GetEntities(); + size_t numElements = entities.size(); + if (numElements > 0) + { + AZ::EntityId parent = entities[0]->GetId(); + for (size_t i = 0; i < numElements; ++i) + { + AZStd::unique_ptr& entity = entities[i]; + auto component = entity->CreateComponent(); + if (i > 0) + { + component->SetParent(parent); + } + } + } + } + protected: AZ::Data::Asset* m_spawnableAsset { nullptr }; AzFramework::SpawnableEntitiesManager* m_manager { nullptr }; @@ -104,7 +141,7 @@ namespace UnitTest { spawnedEntitiesCount += entities.size(); }; - AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(callback); m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); @@ -112,6 +149,37 @@ namespace UnitTest EXPECT_EQ(NumEntities, spawnedEntitiesCount); } + TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_SetParentOnSpawnedEntities_LineageIsPreserved) + { + static constexpr size_t NumEntities = 4; + FillSpawnable(NumEntities); + CreateRecursiveHierarchy(); + + auto callback = [](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + AZ::EntityId parentId; + bool isFirst = true; + for (const AZ::Entity* entity : entities) + { + if (!isFirst) + { + auto transform = entity->GetTransform(); + ASSERT_NE(nullptr, transform); + EXPECT_EQ(parentId, transform->GetParentId()); + } + else + { + isFirst = false; + } + parentId = entity->GetId(); + } + }; + AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + } + TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_DeleteTicketBeforeCall_NoCrash) { { @@ -126,6 +194,170 @@ namespace UnitTest // SpawnEntities // + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_Call_AllEntitiesSpawned) + { + static constexpr size_t NumEntities = 4; + FillSpawnable(NumEntities); + + AZStd::vector indices = { 0, 2, 3, 1 }; + + size_t spawnedEntitiesCount = 0; + auto callback = [&spawnedEntitiesCount](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + spawnedEntitiesCount += entities.size(); + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + m_manager->SpawnEntities(*m_ticket, AZStd::move(indices), AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + + EXPECT_EQ(NumEntities, spawnedEntitiesCount); + } + + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_SpawnTheSameEntity_AllEntitiesSpawned) + { + static constexpr size_t NumEntities = 1; + FillSpawnable(NumEntities); + + AZStd::vector indices = { 0, 0 }; + + size_t spawnedEntitiesCount = 0; + auto callback = + [&spawnedEntitiesCount](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + spawnedEntitiesCount += entities.size(); + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + m_manager->SpawnEntities(*m_ticket, AZStd::move(indices), AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + + EXPECT_EQ(NumEntities * 2, spawnedEntitiesCount); + } + + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_MultipleSpawns_AllEntitiesSpawned) + { + static constexpr size_t NumEntities = 4; + FillSpawnable(NumEntities); + + AZStd::vector indices = { 0, 2, 3, 1 }; + + size_t spawnedEntitiesCount = 0; + auto callback = + [&spawnedEntitiesCount](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + spawnedEntitiesCount += entities.size(); + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + m_manager->SpawnEntities(*m_ticket, indices, optionalArgs); + m_manager->SpawnEntities(*m_ticket, AZStd::move(indices), AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + + EXPECT_EQ(NumEntities * 2, spawnedEntitiesCount); + } + + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_ReferencesAreRemappedForNewBatch_AllPointToLatestParent) + { + static constexpr size_t NumEntities = 4; + FillSpawnable(NumEntities); + CreateSingleParent(); + + AZStd::vector indices = { 0, 1, 2, 3 }; + AZStd::vector parents; + + auto callback = [&parents](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + AZ::EntityId parent = (*entities.begin())->GetId(); + parents.push_back(parent); + auto it = entities.begin(); + ++it; // Skip the first as that is the parent. + for (; it != entities.end(); ++it) + { + AZ::TransformInterface* transform = (*it)->GetTransform(); + ASSERT_NE(nullptr, transform); + ASSERT_EQ(parent, transform->GetParentId()); + } + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + optionalArgs.m_referencePreviouslySpawnedEntities = false; + m_manager->SpawnEntities(*m_ticket, indices, optionalArgs); + m_manager->SpawnEntities(*m_ticket, AZStd::move(indices), AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + + EXPECT_NE(parents[0], parents[1]); + } + + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_ReferencesAreRemappedForContinuedBatch_AllPointToLatestParent) + { + static constexpr size_t NumEntities = 4; + FillSpawnable(NumEntities); + CreateSingleParent(); + + AZStd::vector indices = { 0, 1, 2, 3 }; + AZStd::vector parents; + + auto callback = + [&parents](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + AZ::EntityId parent = (*entities.begin())->GetId(); + parents.push_back(parent); + auto it = entities.begin(); + ++it; // Skip the first as that is the parent. + for (; it!=entities.end(); ++it) + { + AZ::TransformInterface* transform = (*it)->GetTransform(); + ASSERT_NE(nullptr, transform); + ASSERT_EQ(parent, transform->GetParentId()); + } + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_completionCallback = AZStd::move(callback); + optionalArgs.m_referencePreviouslySpawnedEntities = true; + m_manager->SpawnEntities(*m_ticket, indices, optionalArgs); + m_manager->SpawnEntities(*m_ticket, AZStd::move(indices), AZStd::move(optionalArgs)); + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + + EXPECT_NE(parents[0], parents[1]); + } + + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_ReferencesAreRemappedAcrossBatches_AllPointToLatestParent) + { + FillSpawnable(4); + CreateSingleParent(); + + // Spawn a regular batch but with two parents and store the id of the last entity. This will the parent for the next batch. + AZ::EntityId parent; + auto getParent = [&parent](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + ASSERT_NE(entities.begin(), entities.end()); + parent = (*AZStd::prev(entities.end()))->GetId(); + }; + + AzFramework::SpawnEntitiesOptionalArgs optionalArgsFirstBatch; + optionalArgsFirstBatch.m_completionCallback = AZStd::move(getParent); + optionalArgsFirstBatch.m_referencePreviouslySpawnedEntities = true; + m_manager->SpawnEntities(*m_ticket, {0, 1, 2, 3, 0}, AZStd::move(optionalArgsFirstBatch)); + + // Next, spawn all the entities that have a reference to the parent that was just stored. + auto parentCheck = [&parent](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities) + { + for (auto& it : entities) + { + AZ::TransformInterface* transform = it->GetTransform(); + ASSERT_NE(nullptr, transform); + ASSERT_EQ(parent, transform->GetParentId()); + } + }; + AzFramework::SpawnEntitiesOptionalArgs optionalArgsSecondBatch; + optionalArgsSecondBatch.m_completionCallback = AZStd::move(parentCheck); + optionalArgsSecondBatch.m_referencePreviouslySpawnedEntities = true; + m_manager->SpawnEntities(*m_ticket, {1, 2, 3}, AZStd::move(optionalArgsSecondBatch)); + + m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); + } + TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_DeleteTicketBeforeCall_NoCrash) { { @@ -186,7 +418,7 @@ namespace UnitTest }; m_manager->SpawnAllEntities(*m_ticket); - m_manager->ListEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->ListEntities(*m_ticket, AZStd::move(callback)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); EXPECT_TRUE(allValidEntityIds); @@ -199,7 +431,7 @@ namespace UnitTest { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->ListEntities(ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->ListEntities(ticket, AZStd::move(callback)); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -231,7 +463,7 @@ namespace UnitTest }; m_manager->SpawnAllEntities(*m_ticket); - m_manager->ListIndicesAndEntities(*m_ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->ListIndicesAndEntities(*m_ticket, AZStd::move(callback)); m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); EXPECT_TRUE(allValidEntityIds); @@ -244,7 +476,7 @@ namespace UnitTest { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->ListIndicesAndEntities(ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->ListIndicesAndEntities(ticket, AZStd::move(callback)); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -260,7 +492,7 @@ namespace UnitTest { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->ClaimEntities(ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->ClaimEntities(ticket, AZStd::move(callback)); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -276,7 +508,7 @@ namespace UnitTest { AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset); - m_manager->Barrier(ticket, AzFramework::SpawnablePriority_Default, AZStd::move(callback)); + m_manager->Barrier(ticket, AZStd::move(callback)); } m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular); } @@ -307,12 +539,12 @@ namespace UnitTest defaultPriorityCallId = callCounter++; }; - AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(defaultCallback); optionalArgs.m_priority = AzFramework::SpawnablePriority_Default; m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); - AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs highPriortyOptionalArgs; highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); highPriortyOptionalArgs.m_priority = AzFramework::SpawnablePriority_High; m_manager->SpawnAllEntities(highPriorityTicket, AZStd::move(highPriortyOptionalArgs)); @@ -343,12 +575,12 @@ namespace UnitTest defaultPriorityCallId = callCounter++; }; - AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; optionalArgs.m_completionCallback = AZStd::move(defaultCallback); optionalArgs.m_priority = AzFramework::SpawnablePriority_Default; m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs)); - AzFramework::SpawnEntitiesOptionalArgs highPriortyOptionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs highPriortyOptionalArgs; highPriortyOptionalArgs.m_completionCallback = AZStd::move(highCallback); highPriortyOptionalArgs.m_priority = AzFramework::SpawnablePriority_High; m_manager->SpawnAllEntities(*m_ticket, AZStd::move(highPriortyOptionalArgs)); diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetBindMarkerComponent.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetBindMarkerComponent.cpp index c93c09cfbc..bd1cf40da8 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetBindMarkerComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetBindMarkerComponent.cpp @@ -81,8 +81,10 @@ namespace Multiplayer }; m_netSpawnTicket = AzFramework::EntitySpawnTicket(m_networkSpawnableAsset); + AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + optionalArgs.m_preInsertionCallback = AZStd::move(preInsertionCallback); AzFramework::SpawnableEntitiesInterface::Get()->SpawnEntities( - m_netSpawnTicket, AzFramework::SpawnablePriority_Default, { m_netEntityIndex }, preInsertionCallback); + m_netSpawnTicket, { m_netEntityIndex }, AZStd::move(optionalArgs)); } } @@ -90,7 +92,7 @@ namespace Multiplayer { if(m_netSpawnTicket.IsValid()) { - AzFramework::SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_netSpawnTicket, AzFramework::SpawnablePriority_Default); + AzFramework::SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_netSpawnTicket); } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp index 39afa46a19..a7875c2615 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Spawning/SpawnNodeable.cpp @@ -134,7 +134,7 @@ namespace ScriptCanvas::Nodeables::Spawning m_spawnBatchSizes.push_back(view.size()); }; - AzFramework::SpawnEntitiesOptionalArgs optionalArgs; + AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs; optionalArgs.m_preInsertionCallback = AZStd::move(preSpawnCB); optionalArgs.m_completionCallback = AZStd::move(spawnCompleteCB); AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_spawnTicket, AZStd::move(optionalArgs)); From ba02652e6377a022b7588a1c2f59d38063a0646a Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Thu, 3 Jun 2021 10:59:11 -0700 Subject: [PATCH 068/153] [LYN-4200] Fail and log error if required aws config file is not found (#1099) --- .../manager/configuration_manager.py | 7 +- .../resource_mapping_tool.py | 11 +- .../style/editormainwindow_resources.py | 2362 +++++++++-------- .../ResourceMappingTool/utils/aws_utils.py | 13 +- 4 files changed, 1261 insertions(+), 1132 deletions(-) diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py index b679921196..fc188582c7 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/manager/configuration_manager.py @@ -48,7 +48,8 @@ class ConfigurationManager(object): def configuration(self, new_configuration: ConfigurationManager) -> None: self._configuration = new_configuration - def setup(self, config_path: str) -> None: + def setup(self, config_path: str) -> bool: + result: bool = True logger.info("Setting up default configuration ...") try: normalized_config_path: str = file_utils.normalize_file_path(config_path); @@ -63,5 +64,7 @@ class ConfigurationManager(object): self._configuration.account_id = aws_utils.get_default_account_id() self._configuration.region = aws_utils.get_default_region() except (RuntimeError, FileNotFoundError) as e: - logger.exception(e) + logger.error(e) + result = False logger.debug(self._configuration) + return result diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py index e99bf5d441..6a56491b24 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/resource_mapping_tool.py @@ -74,11 +74,18 @@ if __name__ == "__main__": logger.warning("Failed to load style sheet for resource mapping tool") logger.info("Initializing boto3 default session ...") - aws_utils.setup_default_session(arguments.profile) + try: + aws_utils.setup_default_session(arguments.profile) + except RuntimeError as error: + logger.error(error) + environment_utils.cleanup_qt_environment() + exit(-1) logger.info("Initializing configuration manager ...") configuration_manager: ConfigurationManager = ConfigurationManager() - configuration_manager.setup(arguments.config_path) + if not configuration_manager.setup(arguments.config_path): + environment_utils.cleanup_qt_environment() + exit(-1) logger.info("Initializing thread manager ...") thread_manager: ThreadManager = ThreadManager() diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/editormainwindow_resources.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/editormainwindow_resources.py index fb819cac34..67181fa36d 100644 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/editormainwindow_resources.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/style/editormainwindow_resources.py @@ -3649,968 +3649,1082 @@ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ Z\x80d\xdf%\x00\x7f\x12T\x1b\x97qJ\x10\x92\xa7\ \x22:BG\x84z\xfa\x9d{\x88\xac\x1d\xf5-\x8f\xc3\ r\xe1\x95\x00\x00\x00\x00IEND\xaeB`\x82\ -\x00\x00;\xfb\ +\x00\x00C\x13\ \x00\ -\x01\xa2\x08x\x9c\xed]\x09\x5cL\xdf\x17\x7f-\xb4 \ -\xc9\xde\xa2\xc5RD%\x7f\x89HB\x96(;E\x14\ -\xd1\x0fQ\xb4\x92(B\xd6V*d/E*[Q\ -hAE\x08\xadZ\x94\x92\xd4\xb4\xafS\xcd\xf4\xfe\xf7\ -\xbey\xed\x13M\xcd\xd4\xc4\xdc\xcf\xe7+\xaff\xde;\ -\xf7\x9e\xfb\xce=\xf7l\x17A\xd8\x90\xfe\x08ll\x88\ -\x18rI\x18Av\x80\xff\xdb\xd8P\xae\xa5\xb8\xd9\x10\ -D\x04ATT\xf0kU\x04\x91\x1a\xcf\x86\xc8\xc9Q\ -\xae}\xc6#\xc8\x0a\x03\xf0?1\xfc\x9a\x1fA\x88g\ -\xd9\x10~~\xca\xf5\x7f\x9c\x08r\xdd\x93\x0d9\xb5B\ -c\xd1 ^A^p\xebAK\x16/X\x05\xff\x0a\ -\xc1\x0d\x1f\xbdi\xbf\x0fx\xa6\xb0\xde\x92\x05\xf3\xd6X\ -\xa6\x16e\x1c\xb8\xe2\x9a\xe8YR\xa69E\xe7E\xc0\ -\x0a[\xb5\xc9*Zk9\xfb\xb1\x9f\x97\xf2\xd9\xf6\xfa\ -\xbf\xb3[\xcfN\x10/\x1eU5)w\x94\xe4\x0c\x0f\ -\xb9%\x13.]~\x9b%\xad]p\xc1naN\x22\ -\xff\xca[Q*\xe3.}\x9e\xa72o\xdeW\xd7\xbd\ -*\xb6\xec;\x9f\x5c\xcf\xb7\xf6\xf5\xcfmX\x99\xb8A\ -\xc5(qm\xdeL\xcd\xc4\x0a\xab\xb0\xcd\xa4\xb1\xab\xcc\ -\xae\xde)8D0\x8c\x9b\xa90\xf9u\xce\xa0\x1f\x1c\ -96\xabm\x87\x84\x1bg\xe9\xeb\xaaD\x8a\x8e\x5c\xe1\ -\x17\xea\xa7zJM\x8c[X\x83\xf8H4e@!\ -\x9br\x7fs\xa2u\xf1\xba\x8c~\xd3O/\xb7`[\ -Sf\xc9\xf1,|\x9c\xee,\xb9\xd1\xee\xc8Y\xce\xc2\ -\x90\xd8\x09\xcb\xa6\xb0\x17\xf6\x0fB\x84l\x9f\x84O\x08\ -\x8b\xcb\xf0\x0f\xd5\x9d\xa4\xbf\x1c\xb1|\xce&\xf4`\xe9\ -\xe1\x89r\x03\xdcy\x7f\x14\xc8\xb8\xc5\xf0\x16\x85\xf7\xd7\ -\x1d^:)\xf0M\x89\xc9\x22\xb3\x91\x93D\xe4g!\ -\xb3\xbf\xd9\x88(\x8e|:\xc2}\xd0\x9a\x02\x19\x97@\ -;\xc1\xac\x85\xba3\x03?\x82\x0f\x98\x8e\xf4\x09\x93\x97\ -\x07\x1f\x08\xff/k\x9d.\xdf\xaa\xfc\xe3\x9b\xa7\x87O\ -\x0b\x17\x08\x8b{\xb1\xdaB\xcf\xf9\xc2T\xb6\xac\xb2\xfe\ -W\xc2\x13\xc3E\xc2\x07f\xe4\x0e\xb99\xe0\x9e\xed\xf1\ -\xf0kde\x8b\xc5\x16zu\x91\x95\xf0\xaf\xa7m\x9e\ -\xd9\x8c\x1c\xe5\x1d:[\xb52B9\x9ckru}\ -\xfa\xf2\x90\x01\xf1C\xe3\xfb\xab<\xcf\xce\xecG\x92^\ -q\x03\xfem\xfe\x94@\xc4\xf2\xbd\xdf<\xdd\x10\xa4\xd4\ -\x92Cf\xeb\x07Rm\xb8\x0a\xb8\xa5\xc4 >\xb6\xc1\ -\xc8\x00p\xcb\x15\x16z\x02\x1e\x93 -\xb9\xe1F\xb6\ -+Cb%\xec\xd8Cm\xac\xc8\xca5\xbc\x19\xfd\xf2\ -\xf5O\xc3\xef\x8d\xb5\x89>\xf5!s\x80S\xd1:6\ -\x8b:\xeb\xe29!\x03nN\x87\xdd\xe3p_\xe4w\ -`\xcd\xf5\xfa\x1d\xdcz\xd7Gl\xcdH_DR\xb6\ -\xd8\xb0^\xfcq?\x9bh!\xc5\x0b)\xa4\xfc\xff\xe9\ -l\xe7\x8f\xe4L\xe20!)\xd7D\xcf\xfa\xb6)6\ -\xc4\xd2a\x86\xf1\xd8\xc0\xd1\xbe$\xd5e\x1c\x0a\xd1\x04\ -\xbb\xef\x03\xf7\xb0Y>\xb7U\xd5\x1dR\xaa#2R\ -\xda\xee\xed\x14\x8e\xbd\x15\xf5\xe9\x1f\xd4^\xdc\xd0\x83\xfd\ -T\x13\xd88w\xce7\x9f\x9aa\x12\x1c{8v\xd4\ -[\x17g\xa8=\xf7\x10\xd7A\xc0m\xa6\x96\x8eYU\ -{\xfc\xd7\x07\xcb\xac\x17\x96\x9e+5\x0e\x00\xae\xd8^\ -\xb6\xbd\xa0\xe21d\xe4\xb8\x05#\xa48\xd6E\x11\xce\ -\xafZ\xca\x11\x9e3\x88\xc4\x158,f\xa5\xb5\xb8\xaa\ -\xbe\x87\xb0\xaeo\xb4\x10\xd1\xeb\xdd\x8c\x95\xf2\xfd\xf93\ -\xaf\xe4\xe8m5!\xa9\xda'\xccfO\xbf\xb5u\xa8\ -\xf3c.\x95C\xfb\xe2J\xec\xe7\x04\xc8\xda-v\x18\ -\x1f^\x94\xbf\xf9\x7f\xaeI\x88=Z.\xab:)\x8c\ -\x7f\xd2dq\x85\xe5\xeeA\x17UB\xa2\x911j\xe0\ -\x17w\xd3\x97\xfa\x9d\xf7Z\x9e\xca.\xa6\xbcA\xdc\xfa\ -\xb0x\xc2%\xb7\x8f\xb6\x11\x8fM\xd9\xb2\xe3\x87\xab?\ -\xc9\x10\x10\xf7\xcb\x1b\x11\x16G^pW\xd6y?\xf2\ -z\xe4d\xbf\x05\xdeuvr\xab\xb8\x8c=2\xf3\x0e\ -\xcf\xb90r\xc9D$;\xd6*s\xfe\x88Z\xee\x1b\ -\xf3E\xe4\xc6_\xd8\xfe\x8a<\x86\xc3~nJ\x85\x04\ -\xe8\xda'\xaf\x81\x96S7\x8f\xac\x1f\x7fa^\xf8\xc2\ -\x98\xd4\xc3\xe2\xa6B\x9a~2\xd5\xeaa\xecb\x0d\x85\ -\x0fg\x7f\x91\xb6\x9by(8\xac\x9eg\xdc\x1c\xd0\x95\ -\xb7\x06\xd3V\xdc\xae\xbf{\x9c\x7f\xd1t\xb6\xa1.\x19\ -ZR\xbe#T\x0ey\x94L[\x9c;2\xd2\xf0\xb4\ -\x8dA\xb6\xd9\xe38\xe7\x22\xf6\xf7\xf3\x83\xca\x04\x22\xfd\ -\xbc\x9d~l}\xael\xc1\x96\xbd\xd1\xc2h\x91y\xc9\ -\xf0\xc8\xf7\xda6\xd3\xeaBr-\xe5\xa7\xd8D;\xbd\ -\x93\xb5\xfb:\x9c\xff\xde=\xeb/w\x10\xfbk)c\ -O\x9as;\x8d\xde\xf1\x86`\x18p\xb0\x88\xfdu\x5c\ -A\xday\xe1\xe4\xf1\x0b&|]\xe8'\xfd)G\xcb\ -\xcez'[\xba\xed\x9a\xc3\xe2\xf2\x1f\xa4\xb6\x9a\x05/\ -\x9a\x13\x84d/2-\x99\xa7\x91?\x5cb\xa8\x08\xbb\ -Z\xa5\xe9\xff\x0e\x18M\xb1\x09u|'\xbb\xc0[p\ -\xb1\x1f\x9f\xc5\xbd\xb4\x11*\xa4\xe4#\xa2+n\xd4O\ -\xb2\xe3'\x9bs\x96\x9a&\xf3\xfe\xf2\xed'7\x12\xcc\ -\x0b\xfd\x90\xfd[\xcd\x9e\xa9\xeb\x04\xc1\x196\x948\xaa\ -\xf4\x97\xcc\x0b~\x89\xed\x87\xb3\xd6\x84\xc5\x89\xccj\x90\ -\x0d\xd9\xcd\xb6\xe9\x1cx\xda\xc3\xe3'7x*\xcf\xb3\ -`\xfbD\xa8\xb4\xe5\x97\xb8e\xaauG\xf3\x17;\x98\ -\x03SU.\x14\x7f\xe1\x15\xff\xb2\xd7/3\xcf_\x83\ -4X\xe7\x09\xb2\xf7\xb3\xceRq;\x01\xc9\x84\xa2m\ -\xda\xc8\x18\xa3p>ad\x92\x99\xdb\x1an'\xf3\xe9\ -\xe1+\xc0m\xf3I\x83\xa3\x83\x91\x8f\x0b\x01K\xbf\xde\ -u\xde 2\xb7\x80\x88<\xd5\xb0\xe09\xce\xbfTd\ -u\xb4\x839[6\x97\xd5\xe1\xd3\x8f\x11\xbb\x98\x1d\xd3\ -\xc3\x97xr\x9d\x9d\x10\x84L\x10\xbb\xb0\xc5\xdep\xfd\ -\x12?\x7f\x8e\xace\xc43\xeafn~\xd2^\xfd\x14\ -\x9e\xbb\x8d\x0b\x1b\xf2\xd9h\xdd\xe3O\xdf\x9c\x82V\xbb\ -\x1e\x8f\x99\xe0&\x90\xf6\xb5\xde\x1d\x91\xcb=?w\xe1\ -\x01\x85\xbd\x1eN\xd7*\xc3\xac~%\x8eHU2u\ -\xdb\xcc\xbd\xfaR?\x92`6\x9c\xd0\x8e\x03\x96%\xea\ -L\x12\xb7\x13\xf7\x8e\x22\x90>O\xb5Y\xa2\xe2_\xbc\ -\x8aG|\xa0\x93\xba\xdfG\xd1A6\xf9!\xea\xe3\xec\ -\xe4\x12L\x89\xf2\xc8\x04\x82\xcc9\xfe\xc8\x15.\xdfc\ -\x11w\xc7\xc8\x01<\xe2\xf2q\x9cHh\xb4\x90\x14\xa2\ -V\x80\xfde\xec\x9co*\xb6\x22\xa3\xd4\xe7:\xf0\x8c\ -T\xd5\x9f\xac$\x97t\x8aT\xb71\xcaq\xbf\x92\xe4\ -\x05%\x9f\xc9\x8f\xa6=}\xff1k\x95\xd2\xb1\xa5\x85\ -?\x14\xf7\x0c\xcb\xfbj\x9crCQ6h\xd6la\ -\xdb\x9f\xd5R\xdf\xb9\x85w\x9e_\x91&\xec\xe5?3\ -\xd2\xa0j\x08\xe9\xe4+a\x9fs\x81a\x0a\xcb\xa4\xfc\ -\xea\xef.\xe0U\x9be\xfb=D]\xfc\x8b\x91\xa1\x97\ -\xcb\xa3E\x8a\xa3g\xbc~\x9b\x22\xce\x17\xb5n\xd6\xc4\ -\xb7%\x15Z\x81\xd6\x02\xbc\xaf\xa2\xb7\xd8\xf9\xce\x1a\x95\ -}\xeb\x98\xb8B\x11\xcf\x837\xa2\x12\xa3\x9c\x87\xbb\x8f\ -\xde\xfat\xe8\xa8\x1b\xa1\xc3$\xcc8\xce\x14\x1d\xb2>\ -z\xc6D-W\xae*A\xb8\xff0\xdf\x92\xc4\x99\x22\ -r\xde_\x22\xdc\x97re^\x19\xb6Q\xed\xcb\x90\x13\ -{\xea\xe7\xfb\xf9\xf2\x95\xff\xf6{\ -\x83\xd1\xf0|\x99\xfe3\xf9\x14\xad\x9e\xba<:\xa9T\ -\xb6yU\xb8\xd3O\xa9\x80=\xbb\x0dr\x7f\x8a\x11\xcc\ -\xfb\xf3,\x5cud\xb0\x93\xc2|\xcfp$\xc3\xeb\xd7\ -\x12u+\xd7\xbc\xcc=\xeau\x99f\x95\xb7\x8cBH\ -\xfe\xab\xbc\xcf\xbd\xffl~\xdf\xc4M\xa145H\xb7\ -@V_\x22\xf7\xb8\x82\xbf\xe7\xc5\xe8'\xf1\xe5>\xbb\ -O\x95\x97G)\x5c|\x11\xaffvn\xe0\x18\xf7p\ -$\x9e\x0b\xde\xbcf\xca\xee\xa5\xe4\xe3v\xe6\xdb\xfb)\ -\xec\x9d=\xf7\x9aP\x5c\x9c\xc1\xa3\xb9\xaf]\xeem\xd4\ -*\x9b\x17\xfa\x98\xb7r\xb4n\xf4\x0f6\xb1\x87\xf1\x0b\ -\x1c\x86f\xd6\x9c\xd1\xaax\xc4\xbb7T\xee\x1a\xfb\xfa\ -\x83\x5cR\x0b\xaf\x0d\x0c\xe4\x90\xc9\xf0\xe2O\x9a~\xfb\ -\xfdG\xcd\x00)\xfd\x8c\xb8\xd8\xda\x88\xe3\xb5?~.\ -\xe6\x1f\x15\xb3\x9d\xeb\xb4\x99\x9b\xaa\xfdiU%\xd4|\ -\xa1\xf8n\xf4\xc5\x95\xddwr\xf5\x5c\x84\xe5T\x1f\xf8\ -!\xc3\xbc\xcb/\x08(\xa1f:C\xa4\x0fo\x88\xfa\ -1\xa4\xae\xbf\xfe}Uv\x15\xf7/\xa3\xe7{>\x97\ -\x0bpE\x9f\x07\xfd\xfaU\xb0\xc0\xe9\xb0\x00\x12\xf9\xd8\ -P\x81\xf8q\xe6\x01R\x8ed.\xa9\x22_~\x8d\xd7\ -QN\x1b\xb9\x17\x11^\xe6\x17?N\xf9\xbe>y\x98\ -\x93\xe41\xbb\x9d\xe3\xd9\xc4\xe4\xa3\xae\x98Tl8\xb0\ -e\xf4\xb6I\x22!g\x9c\xa7\x8fC\x16\xa8\x8d\x9e\x19\ -\x13\x11\x8b\xae\x8a\xca5x;\xe2b\xbe\x18\xf8\x90\x86\ -ml\xd4\xb6\xe4\x91\x15\xf1\xd2\xbc\x0f\xd4\x1d\xc4\xc6\x0b\ - \x12c\xbf\x1a\x1a\xa7\x1d\xaf\x9d\xfc\xdcwAT\xbf\ -U\xf0C\xa9~\xd3t&\x87>\xb2;\xadZ;\xa9\ -\xe6d\xfat\xa7\xb2\x09\xe7b\xbekZ\x5c\x90\xf3Y\ -\xf3\xf2\xe3[g\xa5\x09\x0f#S\x96J\xc6e\xe8\xbc\ -\xd3\xe5\xb1\xbd\x1d\x93!\xa0\xb5\x8d\xa8\xc2\x15;\x9e\xd3\ -Y\xc2b\xa9\xfe\x85\xef\x1c\x22\xb3\xad\x17\xf9\x9e\xe5\xa9\ -tJ\x1f\xefd\xa66\xd8\xbc\xf4\xa4\xa8k\xcc\x18\x0e\ -\xeb\xace\xe4\xf1\xabf\xecw<&lP\xa7\xec\xb7\ -x\xdc\xa4\x8d\x1aU\xd7\x83fF\x16\xc7\xbd*\x1cd\ -W[\xb9\xd8Ne\xbe\xdd\xab\xe5CR\xe7\x7f\x12<\ -[\x94\xb5\xf3\xd1\x9b n\xd9\xb7\xc1+W\xea\x1b,\ -\xf6\xf0\xbc1\x9cOm\x90y\xd6\xe8,92\xa9\x9e\ -\xd3\xc1%z\xaf\xd4\xcf\xa4\xf1\x83\x1eN\xdc9x\xd9\ -\x10D\x93|\xdd\xee\xc6\xf0\xfc\x8d\xdf\xbe~\x12\xdcN\ -\xd2\xe4#\xbc\x9c\x1c\xef\xe3\xcf\xf3h\xaf\x81\xe3 Q\ -\x8b\xc0D\xd1l]\x9d]V\xc6\xb9\xa1\x86gE\x0b\ -\xf4\xbfpK\xe6\x9d7/K\x5c}\xc5;=&\xe7\ -f\xbc\xce\xfb\xb0\x87\x8e[^&\xf8\x85Jyo?\ -\x8d\xf0\xe7\x07\xef\xd4\xe4\x92V\xe0\xd2z\xe25'\x97\ -\xf7\xc8\xf3$]W\x8b\xb9\xf9Y\x19\x9a\xb36\x103\ -\xef\xff\xf8\x99\xf2Tw\x13\x9f\xdb\xf2\xf7\xb9\xd9\xd36\ -\xfd\xb8\xec\x93o\x1d{\xf6\xd0]\xbe\x13\x07\xf6\xce/\ -\x17\x8a\xd5\xb6\xe5T\x19\xe1kt\xaa\xbc\xb0N\xa1\xa1\ -RC\xc8\x8a=\xca\xcc6U\xe9\xa6_\xaa\xa0~b\ -\x92\xd8\xf1g\x0a\xfeW\x5cc\x07\xe5\xe5^\xfey\xc3\ -\xb3>lmL\x10\x87\xb8\xf9!\xc1/:\xc3\xe2\x9d\ -\x90\x18\x81\xddw\x95\xdc\xeb\xce\xa4\xde\xb2\xb6\xd4\xb9\x94\ -v\x8bTV\xa4\xd0@4\x17\x9a\x16\x15R\xba\xd99\ -n\xdc\x07\xa5\xfa\x1f\xb9)D\xf2\xf27\x87\xc8\x11\xb3\ -.\xa5\xea\xab\x889\xbdg\xd7?\x15G\x18\x9b*\x8d\ -\x96\xad[\xdf\xcf\xa3\xe8^\x9e\x95C\xf2\xa3\x9c\xeb\xdf\ -\xb6d\xeaq\x88\xa4\x1fy\xd2pl\xf5{5v\x15\ -\xa9`s\x03.7\x19\x9f\x9c;q3>\x7f\xba+\ -{{\x87\xe6\xdb\xdc\x87\xa7\xcaG\xed\x93\xe0A\xf4\xec\ -\xff\x1bvU+9\xaa\x1f\x9ag\x9f\x14\xefp\xd8l\ -\xb9\x93x\xde\x84\x1d\xbc\xcf\x86F\xae8)8\xf6\xbd\ -Nj\xb8\xc3\xd5=_\xbel\x9f(\xfb\xb8\xac\xe2\x1e\ -\xafYf\xffxG\x84_{\xf2\x96\xcc\xa8\x19\xa2w\ -\xa7\x99\x06\xdd\x8c\x9f!\x99+o\xfd\xd8p&\x9f\x00\ -\xa2z\xab\xe0\x92\xdczR\xd0\xf9`\x0b\xb3Q\x0d\xdf\ -j\xb6\xac\xb6[\xfd\x92\x0c~\x1fp\x22I*\x13\xd5\ -\x99#k\xb4kF\xa5\xb5\xe6>%\xf7is\xb6\xd4\ -\xe4\xee\x96d\x13{<\xe0xD\xbd\xe9X\xcd\x80i\ -\xe6O\xbe\xcdq\x1b\xb6\xa1\xe1\xd3\x10-n\xd7,\xef\ -\x85\x83\x14\xff\xa7v\xf3\xeb\xcf\xb2s\x0ahm\xca\xd4\ -\xd2\xcc\xb93\xe2\x1ck\xa4\x01!\xc7\x06T\x1c(5\ -\x9a\x12\x22\xab#\xc4c\xc39eD\x80\xcd\x0e9\xb4\ -v\xc2\xe9\x8a\xad\xb1\xa7\xce\x19\xbf:PKj8\xb7\ -NpJ\x88\xea\x8a\x10$\xd2\xf4\xf0S\xbf\xcf\x81\xb6\ -\x11\xce\x87\x84\x82\xdf?.\xde`\x03\xde%\xcf\x15\xa3\ -\xf6\x1ey\xc8\x86\xeam\xf3\xe66\x9a-\x9b\xf9p\xe3\ -\x19u\x84{\xf5]\xa3S\xf2\x16Kn\x89\xe7`b\ -\xe4\x92\xe1\x87\xf1\x91\xf0m\xbc\xbbK5\x1d}8\xf5\ -\xf2\x81\xf4\xd9\xaf.e `\xd4v\x1d9\x14\xfa\xc1\ -\xd1\x80\x0bLs9\xad\x8am\xb1\xb3\x16#\xdc\xf1\x97\ -\xd1\xa3S5\x87l\x9e\x96x0\x03Y\xbd\x8cC&\ -\xf3\x93\x86\xd6\xbc\xba\xfez\xa9g\xb7hM\x1aV\xf7\ -\x5c9\xf2\xc8\xfd\xff~\xda\xeeNP\x8eC\xcf=\xda\ -_\xfb\xe6\xcc\x87\x8b\xda\x0ez\x15\x96\x1cI\xcf\xb4\x9d\ -\x1e\x08\x9b\xc379\xe7\x84\x0f\xf9CH\xc5\xe0s~\ -\xe9\x86\x85\x0f\xf5=o\x0f\x10\x93WUd\x0f;\xbc\ -\x90|\xfa\x85\x96A\x88\xe9\x96\xbb7\xc0k\x1e\xb5A\ -g\xf8\x8f\x0c\xcd\x84\xea\x12\x99Y\x19\x0b\xcf\xcf\xac\x96\ -\x9fn\xc7i\x13#\xe5\xf0\x22\xe9ne\xd5\x00\x93=\ -\xcb\x84vz~\x05\xa4:\xad\x04\x93\xe3\x82\x91\xdc\xc1\ -\x86Q\x04S\x0e\xf8\xcd\x03\xbb\xce\xa5F\x9f\xb8\xe3\xf0\ -@c@\xf8\xb0x\x9b\x1d\xe5\xaf\xd3\x05xM\x12\xfd\ -\x068\xa8}\x0f\x92\x14|\x5c|\xf6\xf2\xa0\xcd\x07\xc2\ -<\x8f\x84=\x5c\xf15\xef\x7f{\xed]\x9c\x0f]\x1e\ -\xaf,\x09Fz\xfe\xbb\xa2M\xa6!!?3\xa3\xe6\ -\x88\x5c$\xae\xf2MJ\x1f\x93[\xb2\xf1\xd8\xfb\xab7\ -w|?\xff\xa1\xbf\xc1\xa0X=\xb3\x0b/3\xce\x9c\ -\x93\xd0\xb1\xe1\x1c:g\xd7\xe5\xc3\x01\xcf\x8d\xde\xe6f\xa2\x16;\ -_\xa6\xefX\xfb\x8e7\xb1\x9f\xcdps#g\xa3\x1d\ -\x9b\xceD\x0e\xda\xf1n\xb8\x8c\xfc\xc3\x10[\xded\xa3\ -\xffI\x93V\xca\x0d\xe0\xb1yz\xf0\xb8I\xd5\xfc\xd8\ -\xed\xa7\xe7]\x10\xcf}h#=\x5c\x00\xd9w-Q\ -z 2`\xf6\xba\xbbg\x0clB\x8c\xef\xef\xb98\ -\xc2f{\x82T\xba\xff\xeeJ\xdd\xdd\x85\xb2w^\xf9\ -D\x14\xb0\xab\xe4:\x1c\xd5\x02\x14\xf8\x92\x02\xd5\x07\x18\ -\xae\xd1\xce\xfa\xbc\xeaV\xae\xa2\xee\x0f1\xb3\xef\x07\xc3\ -\xd95\xf7\xbd\x0b\x96\xd7\xc8\xdd\xe6\x85\x18h\xeb\xbbi\ -\x8d\xf5<\xec\xbc:\x7f\xde\xd5\xc3<\x08\xe1?\xc33\ -\x93\xf6\xf4[6Z\xcf3\xc7\xfb\xac|\xed0\xb3\x9a\ -\xff\x09\x83\xd71\x9f}\xc3;\x99\xe3J5\xa4x)\ -\x1e\x1b\xd3\xcb\xca\xda\x19s2,\x14\xfdL\xf7\xb9\x83\ -\xa7\x8c\xf3\xf1_\x19\x1c\x96\xbeSr\xe6\x85\xbdJ;\ -\xa6?\x9b\xb9\xcb\xa1\xcc\x7f\xd5!\xf6\x07Z13\xe4\ -#N^\xbb[\xffi\x8f\xc2S\xfd\xe7f\xe7=\xd7\ -\x15=\xff\xcb\xc9\xb1\x13\xee\xce|\xff\xe5\xb4\xcc\ -\x5c\xf5\xa2\x17\xe9O\xd7gxp\xec\x90`s\xd4\xcd\ -\xbc!g\xdb\xdf\x8ccn\xbc\xda\xcf\x18S]\xc1a\ -?S\xdd\xcd\xbcC\x92\xd6H\xb1_\xaeY22\xdc\ -\xf9\xdbZ\xcb\xd4\xb3\xaf\xf82\xebv]-V\x7fo\ -\xb9^\xe3\xdd\xdaT\x12Z\xaa\x12#\xefpR\x1d\x11\ -6 \xef}\xb2<\xac\x84\xbcz\x8c\xc6\x81\xff\x89\x8d\ -\x9f\xe1y-\xa0\xb2*\xf3n\xd0\xc7\x99\xe7\x05\x90\xe8\ -\xda\x12\x87\x84\xc3\xc4\x0b\xdb\xcde\xdc\x1e\xd8\x1c\xbe<\ -\xf3\xa3\x97i\xadl\xf8F%\xbf\xcf(\x17\x8f\xcd\xd0\ -C\xdaBz'\xb3'^\x0f\x95\x91Yq\x90OO\ -!4\xcf\x99\xdd+ \x13,g.\x0b\xfb#\xf3\xd8\ -\xaf\xab\xa3\xc4\x15{\xa4u\x13t\xb9\xd6_\x99r\xdf\ -F_\xc7\xf8\xd2\x99G'\xee\xe9\xac\x22;\x14\xcd\x8b\ -\xfc\x1a\x86\x94\x82\xa1\x92y\x1e\xb4\xd6Z\xb4t\x91\xdb\ -p\xc7\xdd\xb6\x15y\xf1o\xf4N\x1e\x09\xbd\xb9\xa2\xb6\ -\xde/\xc5\xcf\xd8`\xd4Pg\xe4Wd\x12Y\xdc+\ -\xf6(\xdb\x89u\x8aO\x8b\xd8\x9f\x1c\xd3\xfa\xfa\xa3.\ -\xbf\xf6\xec\xba\xf4\x1a#\xc33\xe5\xeb.\x98aO\xdb\ -(\xfb<\xd9\x9b4\xa7\xf8\xa5\xe2\xb5\xd5\xe9\xf2\xe3?\ -]~'\xafTc\xad\xb3'S4\xcb\xeb\x5c\x91\xe9\ -\x86mlY+\x05\x90\x0c\xcb\x9d\xdbB\xcb_\xea\xee\ -=\x7f.\xf3\xd0\x1d\xee\xd0J\xce\x83\x95\xd7\x92G\xac\ -\xbcm\x5c\x93\xa9\x11\xe7\xbf^\xb4n\xc7X\xb6O\xe7\ -\xc0\xeaD\x8a\xe3\xab\xfa\x10\x11p\xd5\xf9\x95\xc8\xc8%\ -\xeb\xaf+%k\xc6m\xfb\xa9X\x15\xb7\xc20M4\ -\xfb\x15G\xd2\x06\xb2\xdbb\xf6\xeb\x5c\xea\xeb\x83\x05\xcb\ -\x95k6k\xc7\xe8\x7f\x95\xcd\xe2\xbc3\xd8L\x1e\xbd\ -\x5c\xc0\xd5\x804\x04F\xb9\xc7\xa5\x1a\x8eC\x0e\x06\xee\ -5\xe0\x12\x9dxH5\xd0%\x9e-,\xd4\xd7}\x9e\ -W\xf9>\xd3I\xb2\x8f\x1f\xfc\xfa\xb9u\xfe\x8e\xa5\xca\ -\x01\x0e\xa5\xe5\x13v\x9fk\xb0p6\xda$;\xe2\xc5\ -\xce\xf7\xb2\xc7B_\x7f\x1cj\xa2.\xe58\x8d\xf7\xed\ -\xbe\xf0\xec\x8dKGi\xeb\xbdG\xf2W\xef\xd6\xe6\xd1\ -2,\x0dp\xe1T\x91m\xa8\x9b\xa7\xc4\xb5\xeb\x5c\xad\ -\xf9\x95\xa9\x09o#/\x9f\x9eB\xf6\xb3\xc9\xe8?\xf8\ -\xc3\xc4\x1d\xa7#\x8b^\x0a$*,\xb2\xdcu\xbf\xaa\ -?:k\x09R)1\xecD\xe6\xcb\xd4\xad)\xf5\x1f\ -\x84\xf3\xb2\xcb\x84\x96NV\x9aVz\x99p\x9ax\x22\ -\xdb\x80}\x9a\ -\xb4\xc5\xcaq\x84\xca\x17\xa0\x13\xa5W,\xbb\x15\xb4|\ -,\xd40K\xe6N\xca\xb9\xaa\xe5\xf1\xe4\x9a\xcd+\xbe\ -\x19q1y\xa2se\x92\xd7\xd5\x8a'\x9dsy\x87\ -\x8e_\x94\xffX\x94\xacj!.\xbf|\xb9\x0eg\xe8\ -\xa0=\xe4\xfd'3\xa2f\x8e5yzp\xe9\x98\x93\ -\x97%\xd6\x08).\xfc*:-\xfa\xd9\x86\xfd\xbby\ -\x1eI\xe6e\xef/\x18p\x7f\xbbQp\x99\xd5\xb1u\ -\xe6;x\xf3\xd9+]^\xf1\xc9\xbe\x97\xce1|\xb3\ -qM\xd5\x1b\xff\xb8\xc8\xd9u\xda\x03\xa4\x15\xee\x1d\xb1\ -\x9b9z\xe4\xd5\x9f[\xbf%\xf3\xba\x1a\xe5$\x8e\xbc\ -\xc6\x19\xb9)\xe8\xfa\xc7\xf2\xf8\xc3\xd1`\xad\x89x\xcb\ -!\xecG\xd2\x1b\xed\xd5\xef\xe7\x7f\xa7\x93\x13\x16Z\x1e\ -\xdc#\x1d\xf7\x22\xcd\xbf\xd2\xc6\xe5*\xd8b\xb9\xcf\x19\ -\xef&\xe4\x9dgR f\xe2\xa7\xbf\x8bG\xedY\xc1\ -\x8d\x83w\x87]%\xbb\xfb\x8eCV\xfd\xcf\xe4\xca\x19\ -I\xa3i\xc9_2Vp~\xbb\xcb[\x1e\xfca\xde\ -\xe6\xb4o\x1a\xd6gR\x1d\x143\xb7o\x8bJ\x11\x96\ -\xb9\xec\x1e;>G\xc7[\xe8\xb2{\x0d*X\x1b[\ -\x9ft(5`\x86\x00\xb2\xd38za-\x89(\x14\ -5;\xf8\xaa\x9f1\xa7B\x09A\xb7\xe8#\x9fBq\ -~\xd6\xb1\x17\xe2\x82\xab7\xd5_-y8\xf5\xb0\x8f\ -\xcb\xdb;\x8a\x1e\xca\xa9o\x5cW_\xd1\xae\xaf\x9e\xa3\ -E\xda!=\x98\xf4&e\xed\x15\x8f\x05\xecb\xcb\xcf\ -n\x8e\xbezZs\xf7\xd8B\xd2d;\xd4\xd8N\xd3\ -\xc1\xae\xf6\xa6\xb8\xaa\x8e\xba+Pe\x17s\xaa:I\ -\xc9\xdc9\xb7\xe9\xce\xb9\x87\xaaB\xc5[\x95\xc0j>\ -\xf0\xbe\xb1\xdc\xc1\xc0c@_\xf4\xdeUf\x9a\x07\xd6\ -\xf2\xf4\x06\xfdc\x93\x89\xf9\xb6\x0d\x9f=&\x97\xb9\xe4\ -]\x22.=\x95\xe1Xto\x95\xd9\xaa\xe3\x9e.\x93\ -\xdeo\xf9\xb8\xe6P\xa0\xec\xeb\xe7w\x84\xbc\xcakT\ -\x93\xd8n/\x91\x1a\x18<\xf7k\x0c\xd7\x88\x99k\x93\ -\xdeCE\xe9\xb9\x8fm\x10\x9f/\xf9\x85\x13\xb2\xf8\x16\ -x\xea\xcc\x01\x84\xaf{#>\x8c\xff\xb0\xb5\xe4\x86\x9c\ -\xc9\x08\x85\x15i\x867kW\x0c\x05\xc3\xfc\xc8;H\ -*\xd3\xfa\xf9fmv\xc1\xc29@\xe6.\x22\ -f\xb7\x0b\xbc\x94q\xf8Z\xa8\x97I\xf1\x7fg\x8a\xbf\ -p\x8b\x0f|\xd2\xefe:\xbf\xfe-\xca\xff\x87\xbc\x1c\ -h\xf3$D}\xac\x9d\x5c\x826Q\x1eQ`{\xf8\ -\xf6\x12\x7f\xd2'\x0d\xbf\x8f\xd1\xec\xe1%&\xc1\x1cB\ -\xa6nK\xb9\xf5\xec\x07\x95\xcd:\xf2\xde\xfb\xfa=\xca\ -\xd5-\xb39S\x91\xcd\x14#\xd5\xf9\xa4\xaa\xd7H\x0a\ -{\xc2/\x19\x0f~U_A\x01o\xb2C\x7f\x9b\xcc\ -\xbc\xf3\xec\xb2\xf92\x9e\xe07n\xd9f\x22\x8ae\xba\ -\x8e\x06fn\x1a\xdc7\x12\xa6\x9a\x91\x88\xc8\x86\x93\xa6\ -\x1cv1\xeb\xa6\xbf. \xae\x8c\xe6\x84\x9fF\xe2~\ -\xc9x\xf1\xab\x9e2\xc86#\xf9\xf8W;i\xdf\x0d\ -uU\xe5\x1e\xaf\xe1\x93&\x09\xff\xee\xdf\x7f\x1dA\xc6\ -\x97_\xe2\xfe\xbahB\xf5\xd4\x90\xb4%\xfbo`\xa6\ -\xbd\xbb\xb1\xb32t\x10\xd2\xe8R\x82\xcc\x03~\x89)\ -\xa4\xd7\x05\x95\x8c\xb38\xd1z\xba\xaa\xfd\ -\xedt\xa1\x80\xd09\x05\x15z\xfb\xc0\xbc\x5c\xab{\xb1\ -\xf8\x9e\x80j\xe5\xae\x0b\x99y/\x1f\xcb\xa2\xdb\xe4\x0d\ -\x96f\xf2<\xfe\xf5R^|\x81\x83\xb6}b\xa2r\ -\xbe\x09B\xb4.\x9e\x13~(c\xbd\xa4\xdd\xaf\xcf$\ -K\x9d\x22\x17}m\x04q@\x08f[n\xf0\xdfT\ -'\x9cJ\xfc\xac\xac^\x17\x0em\xe5\x93\x02GK}\ -\xb1~\xa2j\x7f\xeb\x92\xcd\xa9\xc3\xd7\xeas\xf4\x1bV\ ->\x9c\x82d\x1b\x19\x07\x17\xdf\x1b\xae*\x9cS\xac/\ -=\xb7\xf2V\xbfOos\x06\x91\x86\x10\xfd\x8b\xef\x8d\ -P\x0d|_br$`.*\x97?B\xe5h\x9a\ -\xcd\x9e\x90\x80M\xdcg\xd2\xd40\xd3\xf1F\x04\x19c\ -\xa4;\xaet\xcc\x0a\xefz\x19n\xbdyf\xe1\xc3\xc2\ -\xe2^\x84\x86\xc9:.\x1d`C\x14:\x22\xf4\xeb\x93\ -\xb5\xa4]\xa0;_V\x9a\xef\x9a\xc3\x8b\xa7\x22\x08I\ -\xb9\x86\x10^\x14Rr\x82\x7f\x84\x89\xd5\xf3b\xafq\ -\xb9\x08\x1cDM$,\xc1z\x91]\xa0}}\x8e\x99\ -\xcc\xf6\x89\xe7\xd8\x84\xe3r\x06\x11m\x0eh\xef=\xc5\ -\x9fTj\x9f\x99W\xedMx\xf3\xe5\x0b\xfbb\xe3\xc1\ -\x81\xaf?\xa5\x89\xdb\x99M\x16_\x17\xfde\xc2}6\ -\xfe\xb9\xa6\xa5\xe6\xe38\xed\x16\x07\x8f\x7f]G\xfe\xec\ -\xbae\xe2\xbc\x90\x8dpH\xe4\x1e\x1cx{;i\xdc\ -\x00\xf1\x90*n\xe3\x8d\xcf\xf7z\xad\xd5\x8eF\xce\xe7\ -\x95\xf5o\xe0 z\xbc\xab\xe1\x97\x88%\x7f)1A\ -7%\x9e\x91\x1e\x84@\x0f\xc0\xb4R%\xb1EUV\ -;r^F\xe8\xf0\x90QF\ -\x09V\xbcN\xb6Al\x8fV\xeb|O^\xbfS\x94\ -\xb3P\x83t\xf4#\xdb\xc5\xd1UWU\xf5\xdd\xb7\x87\ -\xcfT[{X.\xb0\x9fcL\xce\xa0t\xee\xd9\xa7\ -\x0d'Ip\xbeV\xa8x\x9a\x06\x1e\x1c\xf1kF\x92\ -\x00bljp\xc3\xc0fg\xc8;1;\x1e?\xae\ -\x9f\x95\x06\xd3\x1cL\xe5\xfc\x06\x18?'\xf6\xd3\x944\ -\xffiS\xa80\xd9\xcf\xfbx\x8a\xc5\x91\x10\xffw\x83\ -\x057\x22\xa7\x80\xac\xe4\xce\xda\xf7#\x9dMo\xd0=\ -\x1b%\x97\xaf/\xd6\x0f_\xcd\xa9\x22\x09\xe8\x9fY\xba\ -Q\xd7\xb5\xf8!\xf7\x8dp\x99\xad\x92\xd5~\x9ft\x1c\ -5RC\x10\x9dS\x99\xee\xd3\xec\xe7\x94\x8a\xdd\x118\ -c\xb8\xcf>\xc5\xa2n\xe04@\x93\xd6\x001\xa7h\ -!)\xf6b\xf6\x86\xe1>\x9ft\xc6\x88\xd7\xdd\x18\xb1\ -\x01\x99\x9d\x946\xf1E\x88\xbb\x022\xeb\xcd1]\x99\ -\xac~'\xf2e\x1c\xf8\xad\x03\x07\x97\xb2\x9d\xf9\xa0]\ -\xa6\xe4\xa1\x8c\xcc:\xf0\x9cM\xd2x\xba1\x97\xdc|\ -\x8b\x03v\xbf\x22wm]\xb4\x1f\xfdZbr\xd2t\ -\xa4\xb7\xac\xfc\x04D\xe0\xc0s\xdb\xcf\xe1\xf7\xc3\x85\xaf\ -\xaf\x02\x7f\xf7J\xe4\xdf\x18\xf7\xf0u\x89II\x82\x8e\ -\xbb\xfev}\xc4\xb4\xdc\x92\xc3$\ -\xa3_A\xc0Y>\x9b\x05c\x8c\xc2\xfb/Cd\xc6\ -\x07]\xd5\x9d\xe4x/t\x93\x84\xf4c\x0e!\xfb\x0f\ -\x99a\xbc\x86Kj>\xce\x0e\xd1_\x8e\xc0\xb9\xf1\x83\ -\xdd\xc5\xfe\xbe\xc2\x95e\x93\x85\xd5\xb6>\xf4\xd5\xd4\x9b\ -5DwF`\xbf\x14n\xbf~\x0a\xb5\xd6\xc5\xe6\x19\ -\xfdV\x8b\xef\xe6\xb8.=\xc6HLt\x14\xd7\x15\xde\ -\xb3\xc8\x09\x0eI\x0e\x0e\x81\x86\xa76[3\xb6\x0f_\ -\xfa?\xf6yY\xc6\x91\xd7\xc8\xe1\x9bu\x07\x97N\x0d\ -|\x05\x84T\x81\x8c\xcf\xca\x86\xb9b:\xff\x138\xa9\ -\xb8}3\xf4v.Y\xa8\xb1\xc0_U\xf7\xa8\x14\xf4\ -vR\xdc\x9f\x98\xc7\x12\xc1}\xa1=\xd1\x08Fc\xa8\ -a\x08\x80\x0c\xc0f\x00{\x00?\x80w\x00\xd9\x00\xe5\ -\x00$\x00\xf4\x1f\x01\x09\xefs6>\x06~\xf8\x98l\ -\xc6\xc7h\x08\xb51d\xe6\xd6\x01\xcf\x87\x01,\x008\ -\x06\x10\x0a\x90\x03P\xc9\x04\xe3\xcf\xac\xa8\xc4\xc7(\x14\ -\x1f\xb3\x05\xf8\x182\xed\x5c\xa0B\x1b'>\x87\x0f\x02\ -D\x01\x941\xc1\xb8\xf6U\x94\xe1cx\x10\x1fSN\ -f\x9a\x07T\xf8>\x03\xc0\x15\xe0;\x13\x8c\xdd\xdf\x86\ -\xef\xf8\xd8\xceh;\x0fz\x99\xef\x10\x13\x01\x1c\x00r\ -\x99`\x9c\xfev\xe4\xe2c=\xb1-\x1fz\x81\xf7|\ -\x00;\x01\x92\x99`\x5c\xfe5$\xe3c\xcf\xd7Ss\ -\xa0\x0d\xef\xa7\x00\xf8\x00\x10\x99`,\xfeU\x10q\x1e\ -La\xf4\x1chq\x7f\x0e\x80\x95\x00\xf1L\xd0\x7f\x16\ -(\x88\xc7y\xc2A\xef9@h\xfd\xces\x03\x18\x01\ -\x140A\x9fYh\x8d\x02\x9c7\xdc\x04:\xca\x82\x16\ -\xf7\x1a\x08p\x14\xa0\x8a\x09\xfa\xca\x02uT\xe1<\x1a\ -H\x0f\xfe\xb7\xe1\xfd)\x02k\xad\xef\x0b \xe2\xbc\xea\ -\xd6\x1c \xb4\x96\xf9GY\xbc\xefS\x80\xbc:Fh\ -\xb1\x16t\x91\xf7P\x9f\x80k\x0aK\xe6\xf7=T\xe1\ -\xbc\xa3I'$\xb4\xd6\xf7\xa0N\xc9\xd2\xf5\xfa.\x0a\ -p\x1evZ\x1fl\xf1Y\xb8\xa7d\xed\xf1\xfa>\xe2\ -\x09-\xec\x03\x9d\xe4=\xb4)\xf90\x01\xed,\xd0\x07\ ->\x84\x16v\xc2N\xc8}hWd\xe9{\x7f\x0f\x88\ -8O;\x5c\x07Z\xfc\x0d\xfa\x15X\xf6\xfc\xbf\x0f\xc9\ -\x84\x16>\xa3\x0ex\x0f\xfd\x8a\x0eL@+\x0b\x8c\x81\ -\x03\xa1\x85\xef\x98\x0a\xff\xa1o\x99\xe5\xc3\xfd{\x91\x8b\ -\xf3\x98\x1a\xff\xe1\xbcpe\x02\x1aY`,\x5cq^\ -\xb7}\xf7a|\x11+n\xe7\xef\xc7w\x9c\xd7mu\ -~+&\xa0\x8d\x85\x9e\x81U\x1b\xde\xc3\x18\xd3(&\ -\xa0\x8b\x85\x9eA\x14\xa1u\x5c\xf1B\x02+N\xf7_\ -B\x19\xce\xf3F\xfe\x1fc\x02\x9aX\xe8Y\x1c#4\ -\xe7\xe5\x842\x01=,\xf4,B\x09\xcd9Y9L\ -@\x0f\x0b=\x8b\x1cBs>\x1e+'\xeb\xdfC%\ -\xa19\x17\xb3\xb7i\xe9!\x88\xa0\x84\xbd\x10\xc2(a\ -\x0f\x84\x10\x0e\xc1\x16\x10j\x06\xfc\x1c\xfc<\xfc^\xaf\ -\xd3\xce\x10@\xde\xdfg\x02:\x18\x07\xc8\xbfF~\xee\ -\x97@\x0b\x0f\xc8\xa0\xc5Gg\xa3\xa5\x8e\xab\xd0\xb2+\ -\xdb\xd1\x0a/\x13\xb4\xe2\xeeA\xb4\xc2\xef0Zq\xcf\ -\x0a\xad\xf06A\xcb\xae\x1a\xa0\xa5\xcek\xd1b;e\ -\xb4\xe8\xa0,Zh2\xae\xc5\x9c\xf8\xab\xe6\x02\xe4\xfd\ -;&\xa0\x831<\x07\xff/\x04\xfc+uZ\x85V\ -\xfa\xdb\xa251\xbeh]\xe6\x07\x94\x5c\xf2\x13m\xa8\ -*E\x1bj\xabQ\x94T\x87\xa2\x0dd\x80\x06\xcaO\ -p\x0d\x7f\xdfP]\x8a\x92K\xf3\xd0\xfa\xef\x9fPb\ -\xec}\xb4\xf2\xc1q\xb4\xd4u=Zd5\x15%\x18\ -\x8b\xfe-s\xa11\xff\xbe\xb7\xe9\xa0+\xdf\x0b\xcd\xa5\ -\x00\xcfW\xa3U\xcf\x5c\xd0z\xc0\xef\x86\xaa\x12\x140\ -\x17\xednk\xa8.C\xeb\xb3\xbf\xa0\xd5/=\xd0\xd2\ -\x0bZh\xa1\x854e\x1d\xe9\xbb\xf3\xa0\xb1\xf6Bo\ -\xd3A\x07\xbe\x0bc\xb2\xbd\xfc\x86!Z\x1b\x1f\x82\x92\ -+\x8b\xbb\xcd\xef?\xcd\x85\xda\xe4\x08\xb4\x1c\xac\x1fE\ -V\xf2-t\x05&\x18\x8f\xce\xa3\xef\xd7\xdd\x00\xe3^\ -h>\x11-\xbf\xbe\x0b\xad\xfb\xfa\x1am\xa8\xaba(\ -\xdf\xdb\xcd\x83\xfaZ\xb4.\xe3\x1d\x98\x07\xfb\xd1B\xcb\ -\xc9\x94y\xd0\xdbc\xd2y\xf4]\xdec\xef\x9a(Z\ -r^\x13%~|\x04\xd6\xec\xaa\x1e\xe5{\xbbyP\ -G\x04r'\x14-uY\x07\xf4\x03\xb1\xbe(\x0b\xfa\ -\x0e\xe0;\x0f\xd6\xde\xca\x80\xa3(\xb9\xf8G\xaf\xf2\xbd\ -m#\x97\xe5\xa3UO\xce`kQ\x1f\x93\x05}\x03\ -`L\xe1\xbe\x8c\xf8>\x00E\xeb\xebz\x9b\xdd\xd4\x1b\ -\x99\x84\x12?\x07\xa3\xc5'\x17\xb0\xe6\x00]y/\x02\ -\xf6\xed+\x81N\xff\xbe\xb79\xdc\xa9V\x9f\x13\x0f\xf6\ -\x8c\x1bXk\x01] \x82\x96\xb9oFI\xf9\xe9\xbd\ -\xcdV\x9a\x1a\xa9\xf0;fg\xea\xfd\xf1\xeb\xc3\x00\xef\ -O\xd9%=\x94T\x94\xdd\xdb\xec\xecR\x83v\xa4\xb2\ -\xab\xff\xf5\xfe8\xf6E\x80\xf5\xb3\xf4\xa26\xf6\x1e\xd1\ -\xbd\x81\xbd[CM9\xdaPY\x8c\x92+\x8b\xb0\x9f\ -\xd85\xf8=\xbd\x1b\xb98\x17-\xf3\xd0e\xe9\x034\ -\xf2\xbe\xe4\xccR\xb4>7\x99.Vz\ -qS\xef\xc9R8\x07\x5c\xd7\xa3$\x02\xed6\x8a\x9a\ -W7)\xbaio\x8f}o\x03\xfauN\xcc\x03c\ -\x98E\xd3\xf8A\x1d\x91\xa2K\xf5\xb2.\x0d\x9e\x0fc\ -O`\xdc\x18-\x0d\xc6\xa2\x95\x9c^\xcc\xd2\x03@\xff\ -a\x8c\x1dM\xeb>\xf8,\x94\x17\x84\xfdc\xd1\xde\x8f\ -\xd1\x15\xc1\xde\xe3\xaaPWJ\x1c!\x0d\xad*\xf8|\ -\xef\x8f\x7f\xaf\xf2^\x04-<0\x05\xb3\x8d\xd0\xd2\xea\ -\xb3>\x82\xbd\x82\x22\xf3\xbc;\x98\xcdJ\x01\xad\xcb\x88\ -\xa5\xad\x1f`\xafStH\xbe\xf7eXo\x01\xec\xd3\ -`\xdc\x0c-\xb2\x13\xc6yA\xfb-\xd3\xf0\xbe\xa9/\ -\xc2X,\x1a-6\xe3\x06b%\xb6\x8f`\xd8~\x95\ -\xd9\x01x\x08\xed\xf1\xb4\xb4\xba\x94H\xb4\xd0r\x0a\xf3\ -\xbd3P\x96YLBk\x13_\xd0\xd4\x9f\xea\xe7n\ -\xbdO{o\x8d\x97\xf9D0^/;?X\xa4:\ -\xb4\xc2\xdb\x94y\xdf\x17@W\xf9\xcd=hC}\xe7\ -\xed\x83u\xe91x\xfc(\x93\xcdg\x86\xf3_\x18\xcb\ -\xc7\xa1\xc5\xa6\x0e\xed-L\xedC\x01<,\xb2\x9e\x8e\ -\xd6\xffH\xe8t\x9f`\xdc`\xb1\xfd?\x18/\x06\xde\ -\x15\x18\xd7\x03\xd7\xc0\xce\xb6\x9a7^\xcco73\x16\ -E\xab\xc3\xaft\xbaO\x98>sm'\xf3\xca4\x86\ -\xf1_\x10\xad\xf4;\xdc\xf9}\x1f\x90\xfd0\xd6\x9e\xe9\ -\xc7\x09\xae\x01\xd0\x87EC>B\xd5\xa3S\xcc\xdf/\ -\xbaC\x84&\x9b\x1f\xb9\xa2\x08\x8b\x09az9\x89\xd9\ -\xb3Ti\xf2\x0f\xc1\x18\x03\xc2>\xb1\xde\xa7\xbd\x07y\ -\x0fc,`~eg\x1b\x8c\xc7):4\x8d\xf9\xf5\ -$\xa8\xd7\x1e\x94\xa5\xc9\x8fY\xfb\xe5)Zh&\xc9\ -\xfc}\xa3\xe7\x18\xd1\xa8\xfbc\xfb>\xb0\xbfb\xfe1\ -\x12\xc1xY\xfb9\xb8\xf3}\xc3\xf6\x00L\xb8\xa7e\ -$\xff\xc1\x9e\x07\xf6\xbb\xb3\x8d\xf8\xf1!Zh:\x1e\ -\xed}{o'\xb0O\x02\x8b;\xebl\x83\xf9\x02E\ -Vr\xff\x16\xff\xa1\x8c\xcc\xfa\xd8\xe91\xaay{\x97\ -I\xec\xfd\x9d\x00\xd8\x03\xd4D^\xeb<\xff\xb1\xb5\xed\ -\x1f\xb2\x03cv\x7f\x19\x9a\xf2y\xfej\xfe\xffL\xf9\ -\xf7\xf8\x0f\xd6;\x96\xfc\xc7\xf9\xff/\xca\x7f\xa8\xff%\ -t\xdeVN\xd1\xff\xa4\xfb\xc0\x18uE\xff{\x8b\xf9\ -A\x99\xbfot\x1c#\x9a\xf7\x7f\xa9}l\xff\x17\xd7\ -\xe9\xbe\xd5~y\x06\xe6\x8c\x14\xf3\xf7\x8d\xce\xe3T\xfd\ -\xc2\xad\xd3c\x04\xf3\xb4`\xfcu\x9f\xb0\xff\x1c\x9fG\ -\x9b\xfd\xe7\xcdm\xe6\xb7k\xd3\x1b\x98\xfd\xd7\x9a\x06\xfb\ -o=s\xfb\xfe\x9a\xfa\xd5\x05\xfb\xef\xe3\xd3\xcc\xdf/\ -\x06\x8cS\x99\x9b\x0eM\xf1\x12\xb0\x8e\x1b\xd3\xc7LB\ -\xffO\xd8\xe5N\xf7\x09\xe6\x92\x94_\xdf\xfd\xef\xf1\x1f\ -\xfaJ\x8f(b6@X[\xad\xfe\xfb\xe7\xdf\x03|\ -\x06\xe6o\xc2\xb5\x95i\xd7I\xcc\xff\xfb?\xa0\xcf\xd3\ -\xe0\xff-/@KN\xa91\xff\xba\xc6\x08\x80w\x05\ -\xee\x03a\xad\xcd\xce\x00\xab\xad\xc3\xcc\xeb$\x94\xfd0\ -\x16\x98\x86\xfc0XC\xac\xcf\xea\xfe{E:\x07z\ -\xdc\xa33\xf7\xea\xe5\xb1\xc0\xe2\xbf\x12\x9ew\x9a\xf7\xb0\ -aq\xccF\xa2\xbdO?\xad\xd8?\x16\xeb\xef\x1fa\ -.E\xc9\xcb\xeamz\x19\x8d=x\xee*\x91\x86\xf8\ -O\xa0\xfb\x94]\xda\xda\xf7\xd6~\xa8\xbb]5@k\ -\x93\xc3\x7f\x8f\x94\x08\x94\xf8\xf6.^\x13\x8d\x89\xdf\xdd\ -\xee\xa2\xb1fA\xc6[\x9a\xde}\xa8\xd3\x14Y\xf7\x01\ -\x9bF[\x18\x0aRr6:\xd1`|\x1f\x1c\x9b\xbf\ -W\xbf\x11\xc1\xec\xbdU!.\xb4\xe7\x7f\xc8\xd4v\x8c\x9e\xe2\xbf\xef\x01\ -\xacfnW[\x8f\xc7\x84\xc0\xfa/fR\xd8y1\ -\xb0\xc6TW\x1a\xe9g\x0aZ|\x5c\xa5\xf7\xd7\xae\x7f\ -\x81\xff\xf4:\xc3\x09\xa3]\x14\xe8kK\x80\xcc\xb9\xdf\ -\xe5\xb3\x06\xe0\xf92\xf0\xdc\xa1>\xb7\xdf\xeb\x8b\xfc7\ -\x16\xc3\xce\xec\xc1b\x86\xbaT\xffM\xa4\xb9\xfe\xdb\x89\ -\xf9\xd8^\xad\xbbu\x00a\xfeR\xa1\xe9_\x10\xe7M\ -\xcb\xfe\xbf\xf8G/\xf0\x9f\x12_\x02\xd7Y\xe83\x82\ -6\xf9b[%\xbc\xf6\x9ep\x8b\xf3\xde:Q\xff\xf1\ -\xd5M\xba\xd4\xa0\x85\xb1nE\xb6\xb3\xfa\xb6\xdco\x04\ -V\xf7f\x03\x16\xe3\xf8{\x5cG\xab\x82\xceQ\x8f\xdb\ -\xea\x01\xfeC\xde\xc3\x06\xf3q\xe1\x1e\x8d\xf8)\x08\xab\ -1V\x0e\xcfzs\xdf\x8c\xd5\x94\x87{\x10\xa8\x8b\xc3\ -z\xb0\xad\xea\xbf\xfe\xfcJ\x93-\xf7w\x0d\xd6.\xc7\ -\xf4\xfd\xbf\x81\xf7-\x01\xed\xfa\x9d\x01\xb5\xef\xf6\x04\xff\ -\xe1Y\x11T\x19R\x87\xe5\x9d\xc2\xf3\xc1\xe0yQ\xf0\ -'\xc3\xea?\x97\xe4br\xa4\xcf\xcb|z\xa37\xf9\ -\xdfC\x0d\xd6\x7f/g\xd5\x7f\xff'\xf9\x8f\x9d\xff\xe0\ -\xc9:\xff\xe1_\xe4?\xf4\xeb\xb1\xce\x7f\xf9\x07\xf9O\ -\xae\xc7t\xcc\xe2\x93\xf3\xff>]\x8f\xc5\xff\xdf6\xe8\ -\xcf\x83{\x07\xd6\xf9o\xff\x16\xff)\xe7?\x86`\xe7\ -\x86\xf7\xb1\xf3\x1f\xe9|\x06(\x8d1{}\x9c\xffM\ -\xe7\xbf\xde\xde\x87\x16ZJ\xf7\xb5w\x1e\xf2\x9e\xae\xe7\ -?C;+\xcc\xe9o\x07X\xb3\xc1\x98\x8a\x8f\x96.\ -\xfe\xbf\xfb\xbf\xe1\xffx\x94\xf8!\x90N\xdcnn\x94\ -\xf3\x9f\xc3\xb1ZD\xd8\x99\xf0}\xf7\xfcg:\x9e\xff\ -.\x82\xf1\x12\xda8\xebR\xdf4#-\x0a%\xc6=\ -\xc6b\xe2\xdb\x8d\x11\xf4\xff\x9fU\xc7\xec\x83U\xc1\x0e\ -\xb4\xe3\xa9#\xa5\xe6?U\xff?\xe5\x1c\x19Zrp\ -\xff\xc4\xf3\xfa\xec\xcfX\xdd~\xa8\xd7\xff%\xe7\xbf\xbf\ -\xa3'\xff;\xcay\x81\xe7r\xc0:\x7f\xd4\xe3\x7f\x84\ -1_B\x97\xf1\xbb\xf8\x09cQ\xb4\xd8~!Z\xe1\ -g\x8d\xcd\x03(\xab\xa1/\x02\xb3\xf5\xc1\x9c#R\x1d\ -e\xed\x81\xf9g0n\x0f\xda\x04k\xab\xb1Z\xb4\xd0\ -n\x03\xeb\xf7\xc0\xfcT\xe8\xe7\x801>\xd8\xbb\x0e\xe3\ -\xb41_R\x9f\xe5{# \xef\xef\xd3\x95\xff\x1d\xd4\ -\xf2\x82zq\x87\xfcg4\x9a\xcep\x92\xc0r,\x8a\ -\x8f*av\xf8\xb2\xcb\xdb\xc0\xba\xbd\x1f\xd3?\xe0Y\ -.\x15w\xad\xb0\xdc\xc22O\x03\xa0\xc7\xadA\x8b\x8f\ -)S\xf2M\x80\x0ci\x8e5\xeb\xf3\xd2\xea\ -\xeb\xd8\x0dJ[^\x0fF\xd1\xac\x96\xd7\x5c\xadn\x8f\ -=\xa0-9m\xae\x1bZ_\x1f!\xb5\xbe\x9eKl\ -}-Z\xda\xfazp\xdb\xeb\xac\xd6\xd7\x5c\xe1\xad\xaf\ -9\xda^\xdb\xb4\xbef\xfb\xd35\xc2j\xac\xc6j\xac\ -\xc6j\x0ci6\xad/\xff(\x8f\xc3[_\xb7\x93\xef\ -Y\xad\xaf\xb9\xfe\xb4~\xb4]o\xda\xaeGm\xd7\xab\ -?\xado\xed\xd6\xc3V\x04q\xb5_O\xdb\xae\xb7m\ -\xd7\xe3\xb6\xebu\xbb\xf5\xbc\xf5z/\x05~\xa8 \x94\ -qeC\xc4(\xbfWAhj\x1d\xe8zj\xb8N\ -\x13\x86\xeb9\xd5\x00\x0d\xbd\xa0k5\xe0\xcf\xce\xc6i\ -\xb1\xc7ik\xa7c\xd1\xda\xa8\xf4[\x08\xc0\x10 \x02\ -\xa0\x94\x09\xf4\xcc\x8eP\x8a\xd3h\x88\xd3L\xf38\xb4\ -\xf9\x0e/\x80.@\x5c/\xf1\xb8;s#\x0e\xa7\x9d\ -\xb7\xb3c\xd0\xa6\xef\xe2\x007\x01j\x99\xa0?]E\ --\xde\x07\xf1?\x8dA\x9b\xbe\xcb\x13\xfe\xae\xbc\xe1(\ -\xbcOT\xc7\x80J\xdf?1\x01\xcd\xf4\xc6\xa7\x8e\xc6\ -\x80\xd0z\xce\xffM|\xa76\x0f\x9a\xde\x856}\x87\ -r\xe2&\x13\xd0\xc8h\xdc$\xb4\x91\x898\xa0\xac\xec\ -\xcb\xb2\xae\xb3\xa8\xc5\xfb\xdav}\x8fc\x02\xdaz\x0a\ -q\x84\xd6\xfa\x01\xd4\x17\xfa\xd2\xfa\xde]4\xe0}n\ -\xd4i#\x98\x80\xa6\x9eF\x04\xa1Y\x9fgf\x9d\x96\ -Q(%4\xefez\x9b\x96\xdeB\xe3>\xae\xe7\x9e\ -\xb9\xb7E}Fx\x0dkG\xc1\xb3R\xe19R-\ -\xcfn\xeb\x99\xbaB\xb0\xeft\xac\x93\xdcQ\x9f[\x9c\ -5xT\x09\xabOZ\xf9\xc8\x1e\xady}\x0b%~\ -x\x88\x12?=\xc1\xce\xba\x85\xf5\x87+|-\xd1R\ -\x87\x95X=SJ\x9dJ\x86\xd6\xd5k\xdc\xbf3\xee\ -\x19\xf0\xbc=\xf3\x89X\x9f\xb1s\xd7\x8a\xb2)\xb5y\ -\x7f\xd3\xe0Y]\xf5YqX\xed\xe8\xe2\x93\x0b\x9a\xe7\ -\x0d\xfd\xe9c\x9c\xed\x02\xf2\x1c\xcc\xed\xd2\x8b\x9b\xd0\xda\ -\xa4\xb0.\x9f)J.\xceE\xabB\x5c\xd0\xa2#3\ -\x18q\x9e4\x83\xfa.\x8c\x9d\x93\x01\xcf\xf1\x86\xf5\x96\ -\xe9\xd1`\xbdfx\x86\x1f\xe5\x19L\x5cs\x0c\xf4\xbd\ -\xc8F\x11;'\x86\xde\x0d\xd6\xda\x84u\x8c)\xf5\xf6\ -\x98p\x0c`\xdf\xc1<\x85\xf3\xbd3\x0d\xd6\xe3&W\ -\x14\x82~\x15\xa0\x0dU`\x9e\x90\xea\xff\xfc\x1d \x1b\ -*|,z\xbf\xaf\xed\xfa.\x82\xd5Cl<\x93\xb2\ -C\xfa\xabJ\xd0\xda/\xcf\xd0\xca\xfb\x87\xd1R\xd7\xf5\ -h\x89\xbd\x1aZ|B\x15-9\xbb\x0c-\xf3\xdc\x81\ -\xad\x01\xf5?\x12\x01\xb3\xc9\x1d\xdf\xa3\xb2\x18\x93\xa7\xcc\ -Vs\xb5\xf2\xe1IJ\xaduj\x0d\xc8|b\xdc#\ -\xb4\xd4iu\xeb\xba\xdbMg\xb4\xe2\xf5\x9a\xc18\xc2\ -z\xa2\xb0\xae;\xa9\xe0[\x87c\x00\xcffg\x9as\ -\xb6\x01\xed\xf0\x9cQrY~\x87<\xaf\xf4\xb7E\x0b\ -\xcd$;'\xc31}A\x18\xabo\xff\xbbw\xa9&\ -\xca\x0b%\xec\x97\xe8\xfd\xfe\x03\x1a\xe0Y-T\xfb^\ -]\x86\x9d\xa5\xd1\xd4/\x1a\xc7\x15\x9e\xd3[\x9b\x10\xda\ -\xe1\xbda\xed~\x06\xac\x8b\xb4\xf1\x1e\xbc\xbb\xe4\x8a\xa2\ -\xf6\x04\x92I\xd8\x99Q\xd8\xb9\x02]\x95\xd7\xe0\xfe\xc5\ -v\xca\x14\x99@m\x0e\xc4\xf8R\xf4\xe7\xde\xea?x\ -\xff\xaa\x82\xcfS\xa5\x0d\xd6\x0b.\xb4\x9c\xd2}]\x1e\ -\x8cA\xf9\xf5]Tu(\xa8\x1f\x15\xdb\xcd\xed%9\ - \x82\xe9\xb6\xf0\x5c\x94vs\xb3\xbe\x96r6(=\ -\xe6&\x5c[\xcc\xa4\xa8\xcb\x02 o\xcbo\x1b\xf7\xce\ -;\x00\xc6\x1c\xae]\xd4\xe4^}N\x02Zd%G\ -\xbf}\x1c\xe8\x1f\x5c\xf7\xb1\xf3<\xda\xbe\x03\x91\xd7\xd1\ -^\xd1\x87\x00Me\xee:T\xcf\x15\xaeys\x9b\xce\ -\xcf\x12FKN\xa9a\xfaR\xbb\xf7,%\x02;\x9f\ -\xa9\xe7\xfb/\x08\xf4Q\x13\xaa<\x81\xeb\x1d]\xe7$\ -\xd4\x0b\x0e\xca\xa1\xf5\xb9I\xed\xe7\xda\x8f\x04\xb4\xf0\xa0\ -l\xcf\xd7\x22\x06\xfd\xaf\xbc\x7f\x84\xfa;y\xcb\x98\xa2\ -\xcf\xd0\xedy\x14\x19@M\xd6\x90\xf23\xa8\x9f\xc1\xc4\ -\xea?\xc3\xfb\xdf\xe1\xfc\x0f\xe8\xd9\xf9_\xd4+\xf3\x1f\ -\xc8?7\x1d\xaa\xf6\x1cx&\x13E\xef\xa1\xd7\xb3\x84\ -\xb1\xbd\x12u\xf9\x17\xd9;\xf2\x0f\xae\x7f@7\xab\xcb\ -\x88\x05s0\x1d%\xfdJ\xa3\xa0 \x03;\x17\x0d;\ -G\x8c\x9e\xeb\xdf\x1ds\xea\xeb\xdf\xab\x1b\x0c\xe4q\xa3\ -M\xb6\x05Z\xeaZ\xc6b\xd8:\x0f\xf7lE\x87p\ -\xc0\xff\xc3\xf3\xb4\xe8\xa5\x97\xfeQ\xff\xd9\xcf\x18\xfd\xc7\ -X\x14\x9b\xdf\xd8\xf9Q\xf0,)\x88\xbb\x07\xd1\x923\ -K[\xf3\x95\xd1u\xf1\xa1\xfe{m'u\xfd\xb7$\ -\x97q\xfb`\xc0?h\xabh\xdb\xaa\x9e\x9ci\x1eo\ -l\xaf*\xf8\x1bt\x93/p\xffsL\x19\x93q\xd4\ -\x1a\x11\x9e\x11\xca\xa8\xfdO\x87\xfd?\xdb\xe4\xa3\x80v\ -\xce2\xf7\xcdh\xd9%=*\xd8\x8a\x96:\xae\xec:\ -}p\xff\x0b\xd65x\xfe,\xb5\x86\xed\x7f]\xd73\ -N\xf7\xff\x13\xff\x01J\x9d\xd6`t`g\xedA\xfb\ -]K\x00Y\x05\xd7k\xec\x8c\x90&\xfd\xbc\x13\xe7n\ -\xe1\xfe\x92b\xfb\x05\xe0\x9d\x7fI\xb5\xef\xb0\xd5D\xdd\ -a\xac\xfd\x03\xf6\x9f\x8a\xed\x01\xfa%\x9a\xfa\xef\xbc\x96\ -r\xde`\x07\xad\xee[l\xab\xfeC\x1bP\xa1\xe9\x84\ -\xf6\xe7\x91\xb5\xb4\x7f\x01\x19Zq\xef\x10\xa6\xd7t\xd4\ -Hy\xa9\xe0\xbd\x9f\xc7\xd8}/\xe8\x7f\xd53'\xfc\ -\xdc\xcf(\x0a\xc0\xff)\xba]'\xfb\x9f\xd1\xa2\xffP\ -_\xf0\xdc\x0e\xe6s(\xb6?(\xbd\xa0\x05\xf64\x8b\ -\xb0\xf3\xd4K\xce5\xda?\xddp\xfbg\xc7\xe7\x06c\ -\xf6Ox6h\x0f\xec\xf9\xb1sop\x9ea\x806\ -\xbc\xc69Gs\xff\x05\xb1\xf3\x84\x9b\xfa\x01\xe49\xb9\ -\xb2\x08\xb3\xebc~\x92N\xdb\xbf-\x19\xde\xef\xd6\x10\ -i\x83f\xf9D{\xff\x8d\xa9\xea0\x9diL\xe7\xff\ -\xe8\xc1\xfeC\x7f(\x83\xfc_\x9d\xf3\x01\xb6\xfa\xcc\x1ea\xccw\x00i\ -\x86\xf1\x81\xe4\x92<\xea>\x7fR\x1dJ.\xfa\x81\xe5\ -\xcb\xc2\xf83,_\xaa{\xfc\xe8>\xed\xe0\xf9%\xa7\ -\x97\xa0\xb5\x9f\x82\xd0\x86:b\xa7\xfd\xb7\x0d\xc4J\xcc\ -\xb7\xd7\xbb\xb9Z\x22\xd8\x98\x93\x08Y\x9d\xa6\xbbm\x83\ -~/,\xd6\xaa\xa7\xfb\x00\x9e\x07\xe3b`\xec\x03\xd5\ -\xf1\xad\xa9\xc0b\x81\xb0\x18\x9d\x8c\xb7X\x1cjG\xf1\ -\x080\xf7\x9a\x92/\xd5C}\x801\xbbg\xd5QR\ -av;Z`\xceHu\xd8%,\x1f\xb0\xe8\x90<\ -%\xc6\xc6L\x0a\x8bw+u\xdd\x80\xe5\xc6\xc3\xbc\xb9\ -v|\xf8\x91\x88\xc5\xdc2\x9c\x0f{)\xb9=\xd4b\ -\xef\xea\xd2\xdfb>jJ\x1f\x85Z\xf8\xc4D\x9a\xfd\ -\xbbX\xee\xf7F\xaaq\x8b5\xd1>\x98\xfcb\xec\xd8\ -\xc3\x98\xd1]\xedb3\xea\xd2\xa2\xb1\x1a\x04\x9d\xf2_\ -\xc3\xdc\xb6Sj\xedr\xcf`|\x02\xe4\x11#s\x8e\ -\x0aM\xc6\xb7\x1b{(/a\x9e%M\xcf\xc5rt\ -6\xb7\xcbC\xc7\xe2\xd3\xb18\x22F\xcc\x1da\xacn\ -\x01\xcckn\xd9\xaaC]\xbb\xe6\xd7\x07\xeb\x18\xcc\xf3\ -k\xf5.\x17|\xa3\xd4\x04`\xc4{\x00\xe3tn\xec\ -n\x95\x83\x0c\xf3\xb3i\x1e\xfb\x16\xf7+s\xdf\xd2j\ -\xdd\x80100\xfe\x8f!s\x08\xdc\x13\xe6]\xb6\x92\ -\x1b9\x09X\xecI\x97\xc6\x1f\xcb\xe9\x9f\xd9N\x8eU\ -\xf8\x98\xd39\xc7\xa5\xf9y\xd5//\xb5z\x16\x8c%\ -\xc2\xf4\x80.\xdd\x0f\xc82\xcb\xc9h}\xf6\xe7V\xf7\ -\xac|x\x821\xe3\xdf!\xfd]\xcc\xd1\xe8i\xfa\xa9\ -\xcd\x9f\xdc\xa4\xae\xe7\xd8t8\x7f,\xe84\x7f\xda\xc7\ -e\xc2x5,'\x05\xc8\x09\x08\x18?\x08s5\xbb\ -$/:|\x7f\xb5\xbb=\xfeX|mcl-\x8c\ -\x93\xc3e2\xfc=\xd4\x05Z\xa2\xcb\xf3\x07\x93\x9f>\ -\xad\xe5'!\x13\xc8O\xc5\xee\xc9O@#\xd4a\x1a\ -\xe3\xa3\xe1zU|lNs\xdc\x9a\xe1\xe8\xd6\xe8\xca\ -\xbe\x0a\xcf\xb1j\xbf~\xf9t{\xfd\x82\xe3\xdd2\x9f\ -\x0e\xea\x92P\xc7\x87t\x16YO\xc7t\xc5\xd6X\x0f\ -t/\x15\x9ah\xa7\xae?T\xd0E\xf6c\xf4\x83q\ -o\xbaou\x19F\x7f\xc1\xeeQX\xae\x14\x9c\xa3-\ -\x01\xf7U\xadr\xa5\x1a\xe3\xee\xa9\xeao\xa2\xd8\xfc\x86\ -\xebF\xdb\x86\xe5\xdc\xd3A\x7f\xc3t\x9c/O1\xba\ -\xa1\xae\x0b\xf7'0\x9e\x14\xa3\xdf\xf7@\xbb\xe7b\xcf\ -\x8e\xf2\xc6i\x17\xc1tP\xb8'\x81\xf9\x02Pw.\ -4o\xa3?W\x16\xb7\xfb>\x94ct\xcb\x97\x07c\ -\x04\xf7\xd90\x86\x1f\xf2\x19\xc6\xaab\xef\xb0\xa1\xe0\x9f\ -\xe9\x872\x16\xec\xd7!_`\xce\x1c\xdc\xbb\xd4e\xbc\ -\xeb\xc4\xfee=}\xf7/-\xeb\x915\xdewOg\ -\xe9w\xa4\xfa\x19j\x8d\xa1\xfb\xc7\x969Xx\x9c5\ -\xccS\xa3J?\x94\x1b4\xd0\x8f\xed\xdf\xdf\xde\xa3\xc7\ -\xfe\x9d\xba\x0d\x02\xe6\xbb\x80\xb5\x11\xe6\xb7\xc1=:\x16\ -\xf7\x0b\xd7\x1b\xb0~\xc1\xf9@\x99\x1782\xdf\xa3\x95\ -\x0fN4\xd1\x0fk\xa8Q\xad7\x83\xd9Or\xe8m\ -?\xa1n\xbf\x82\xba\xf2\xcd=\x18\x1d\x98\x8e\x0c\xf6\xbb\ -\x94Zo\x12\xf8\x9e\xb65\x9a\xe5\x86\x08\xf6\xaeR\xec\ -W\xb6=a\xbf\x0a\xeb\x90~\x18\x93\x0e\xf8L.\xfd\ -\x85\x96\x9cY\xd2B.\xb7\xcd\xfbhCG\xd3\xbck\ -c;d\x8c\xfd\x90\xba\xfd\x16\xce\x1f+9,\xcf\x0e\ -\xc6\xe5C\x19\xc8d\xf1\xa9\x8d\xf6\xdb\x8e\xed\xe7\xadb\ -\xc2\x99\x8av\x94\xd0l?\xef\xeb\xfe\x8b\xbe\xee?\xfa\ -\x1b\xfcw}\xd6\x7f\xda\xd7\xfd\xd7\x7fC\xfc@_\x8f\ -\xdf\xe8\xcb\xf13X\xfc\xd0`\x04\x09\x87?9\xf0x\ -#\xb6\xe6\x9f\xac\xd6\xbdf\x03\xffi1\x9e\xe1\xf0'\ -G\xf3\xb8\xc38-1\x84r\x84OS\x9c\x16?\xf5\ -{\xb5\x99[C\x01\xb6\x01<\x05( t\xef4\xces\xda\xbf\xdf\x14\x0b\xd1\xa2n\x09\xed\xb6\xde\ -\xc6w\xac\xf3\xdf\x81\xf5\xb1\xc1\xfe\x14\xdaN`\xbd\x10\ -X[\x01\xd6\x0d\x84\xf5\x10\xb0\xfaA\xb4\xd1\xd1\xf9\xf7\ -\x1b\xdes\xbf\x04\xb6\xd7\x845>0_\x15\x16\x8b\xd0\ -\x80\xd5^\x806)X\xbb\x02\xda\x11\xa0\xed\xbd\x93\xfb\ -\xb9N?\xbb\xd0R\x1a\xcb\x8dn v\x9c;O1\ -@\x90\xb1z\x11t\xb3Ya\xb5\x84$1\xfbX+\ -\x93A\xc17\x94\x18{\x1f\xad~~\x91\x92\xeb\xfa\xfd\ -S\xab\xbaV\xd0\xfePd;\xab\xfb4\x80\xefc\xb6\ -\x192%\xee\x03\xda\xba\xaaC/`6\x10,\x07\x18\ -\xab\x87K\xc9\x93\x866LX\xdf\xa7\xc9v\xd3]\xbb\ -#\xf4C\x1cV@I?\xbf\xe2\x9d\xae\xc7\xf2\xb01\ -;r\xdb~\xe1{\xd22\x8f-M5\xb7\xa0\x8d\xa0\ -[v\xdbF[\x09\xeeW\xacM\x0e\xa7\xd4\x06\xf8\xdd\ -\xfc\x06\x7f\x83\xf9\xd6Mc\x80\xd5z\xec:\xef\xab\xc3\ -=\x9b\xee\xd5)\xff\x0b\xb4a\x9fY\xda\x14\x8b@\xa9\ -g0\x09\xed\xd2>}\x9f\x18\x16\xf7C\xe1{5V\ -;\xe2\x8fc\x89\xd97\xe41\x1b)e\x9efb5\ -q\xbb\xe4\x87\x02|\x86g\x0d`\xcf\xaf'\xe2\xb6T\ -\x06?\xbfe\x8d\x1b\xc8\xcb\xe0\xf3\x98m\x0e\xde\xa7\xcc\ -\xd3\xe0\xcf\xcf\xa76\xfe\x16\x9d\x1c\xff}\xe2\xd8w\xa1\ -\xdd\x15\xda\xd5\xe1\xfbE\x891\xa1\xd4(\xc3\xecq\x7f\ -z\x9f!\xcd\xcf\x9c\x9b\xe7_\xa7k\xadQ\xea\x81C\ -\xb9\x01\xe5i\xed\xe7`L\xdeB\x9f=\xa4\x09\xc3Y\ -uJ\x9d4j9\xd5\x8d\xef\x9f\xfb\xe6\xa6\xd8\x1f\xca\ -\xfb\xd7I\x9f\x1bV\x8f\x5c\x1a\xad\xcf\xfeBy\xd7\x92\ -^b\xe3\x81\xc9\x5c s\x1a\xaa\xcb1?\x0cVK\ -\x06;\xa3A\x8a\x22\x07\x9a\xe4\xcf\x14\x8a\xfc)n-\ -\x7fh\xf2A\x03YU~\xd5\x00\xab\xe5\x0d\xe5\x08\xcc\ -\xa3\x87\xe3\xd7\xb2\xc1z\x1aX\x0d\xe1\x10W\x94\xf8\xf1\ -!\x90\xbfn\x1d\xca\xdf\xe2\xae\xc8_\xd0\xb7\x82\xdd#\ -)\xfe7\xd0\xaf\xb6r\x1f\xd6a\x87\xf7\x84\xcf\xa6\xda\ -h_\x7fZ\xaf\x81\x80\xe70n\xa2\xe4\xf4\x22\xec\x1a\ -\xca[\xe8\x83\xa9\xcf\x89\xc7b\x83\xca\xaf\xef\xc6\xee\x0b\ -\xfd\x0aX]\x94\x86n\xaf\xbf\xcd\xfa\x07\xceG\xf8\xac\ -\xda\xc4\x97\x18?0?+\xb8_\x13p~\x16\xdb*\ -\xd1K\xffh\xa5\x7f\xc1\xda\x19\xe5^&\x98}\x1f\xca\ -\xbf&\x1f[\xdb\x1ay\xf4\xd3\xbf\xda\xeb\x9f-\xebm\ -0\x0e\x8d\xfago\xeb\xdf\xbd\xbd\xff`\x86\xfdW\xaf\ -\xed?{{\xffm\xd3\x8b\xd6\x18\xf8lh\xa7\x80f\ -\x091\xa4\x85\x9d\x82\xb3\xfdgq\x9a\xc7\x00\xb8\xe1}\ -\xfa\x9d\xed\xae\x01\xff\x8c\x1b\xfe\x9d\xc6\xef\x06ua\x0c\ -\x83Z<\x97\xca\xdf)g/4\xe9,\xd4\xef\xd1H\ -s\xeb\xdf\xc3so\x80|\x85\xb1\x7f%\x0e\x9a\xcd:\ -}{9\xd6\xbe\xbf0\xbe\xfa\xec2\xac\xde l\x18\x9b\ -\x02\xfd\x96\xd8\xd9\x22\x8dgl\x18R|\xe1\xf0\xb9\x94\ -x\xd56\xf47\xeeA#\xaea\xeb\x1e<\xaf\x07>\ -\xa7\xd4U\x0b\xd3\xb9\xe0zU\x1d\xe1\xf9\xbb\xf1kh\ -\xf4\xe1\xc28\x22\xe2\xbb\xfb\xd8\x99$\xf0\xfb\xb5\x89/\ -(\xfe\xd4\xdf\xf3\xaf\x00\x8b\xedv\xd3\xc1\xc6\x16\xae\xb5\ -X\x1c4\xb4\x05\x00]\x03\xc6v\xfca\xfeP\xe6/\ -\xd4\xd9\xb0\xfd[\x8b\xf5to\xa7\xe6ow\xdf\x9fn\ -\xbd\xbf\xddm\xff\x07:J\xaf{\ +\x01\x9f\xd1x\x9c\xed\x1d\x09\x5c\x8c\xdb\xf7\x9bR!\xd4\ +\xc3#)e\x8dl\xf9{\xc8Z\xf6}_\x1f\x22<\ +\xbb\x92\x84,\xd5\x90%d\x97\x9d,E$B\xa4\x92\ +\x22\x22k\x12\xd9[H4\xed{\xd3\xcc|\xff{\xee\ +\xf7MM\xd3LM3\x93&\xba\xbf\xdfy\xbdI\xf3\ +}\xf7\xdes\xee\xd9\xef9\x04\xc1 T\x09\x18\x0cB\ +\x9f\x98\xa7M\x10\x0b\xd0\xff3\x99\xd4\xe7\xb65\x19D\ +\x18\xfa\x9d\xa9)\xfdy\x00A\xa4\xb7`\x10FF\xd4\ +g\x8f\xd6\x04\xd1d>\xfa?}\xfa\xb3&A\xdc\xdb\ +\xc1 45\xa9\xcf\x8bj\x10\xc4\xe2\xe3\x0cb\xfb\xb8\ +1C\xeb\xd6\xd6\xae\x8d\x1e]w\xf8\xb0A\x13\xe0_\ +\x01j\xc2\xabgZ{\xa0wj\x1b\x0e\x1f\xd4\x7f\x92\ +\xed\x87\xe4\xcf\xa3\x975\x88\xfa\xa2\x9a\xf6\xa8\xd5\x18+\ +\xa2\xc1\x86\xe8e\xdeM\xe3w\x5c>1\xe4\xb9\xd9?\ +\xb5/\xd5\xb09p\xd0\xccP\xe5\xcc\xe5'\xdb\xa6]\ +\xf3h9\xcd\xac\xd6\xf8I?\xaf\x98\xaeh|\xd9P\ +\xc9\xac\xf9 \xb7\x05C\x0f\x8c\xaeU\xbf\xc5\x88\xc6\xcf\ +'\xef\x98\xda\xff\xf9\xf1\xd0eg{t\xeb\xb4\xeb\x80\ +\xf1\xf6\xe8\x87\xcf\xb4\xe6-{\xa4\xd75\xd3\xa4k&\ +\xa7\xbb\xe9\xf4\xb4\xf4w\x09G3\xbb%\xe4Y\xfb\xe9\ +8=>~\x8c\x11\x9c\x909\xfcp\xc8\x94\x93\xd7n\ +\xae&\xec\x08\xe7\xd9\x8c\x98\x06\xdc\x97\xdf\xec\xdb\x11\xe4\ +\x1b\x87\xa0\xd3\xe4\xda9\xad\xbf\xec\xdb\xdf\xe9\xc8I\xf4\ +\xf7\x1b\xfcf\xbex\xc3\x08o2\x83\xe58%\xcc\xe4\ +\x95C\xb2r\xfb^.\x8765\xaa\xa9\x1e\xae4\x17\ +\xfd\xdd5}\xb3\xb6\x9e\xb7\xffG\xf4\x9a\xb7\xd4\x8c\xd8\ +\xca8\xa1j\xa5z9)\xf2HC\xe6\x05b\x01c\ +\x94\xd7\x83\xde\x87\xdc\xd5\xffk\x14U\x83i\x7f\x98\xac\ +=\xfda\xea\xfeN\x1a~\x1f\xfe\xc7lG\x98\x18\x07\ +\xae\x8a\xf9A\x84\xa7f5>=\x99\xd3\xe9g\xc6^\ +\x83\x8e\xcay\x8c`e\x83[ut\x9a\x10hns\ +\x88\xd9\x03\x97~ip1\xae\x1d3uJ\x9c\xee\xc4\ +\x08\x95\x8b\x87\xe6)\x99\xea\xdd\x0c\x22\xbc\xe2\xd6\x0c?\ +\xbc\xcdc\xd3|\x22\xba\xff\xd2\xbf\xdd\xdc\xd4'n\xcf\ +`\x9c\x9e\xca\xd1\xf2\xd9\x11\xdd\xc9\xac\xd9Ym\xb7\xd3\ +*\xfdg\xbe\xd1\x1f\xd7\x0b&\x16\xcd\xfc\xdb\xf5Dg\ +\x15\xaf\xa5i\xbbl\xfa\xefh\xd7\x84X\xa7\xe7\xa0\xb3\ +,\xf1@@\x07e\xad\x89\x8b\x9dM/\x12\xe1C\xb3\ +S\x1d\x1d\xd7\x7f\xb3\x1c\xcb\x989i\xce[\xfd\xc3O\ +c\x996\xcd\x99\x1bV\x92k\xbc3\x0e\x14\x9cd\xa4\ +\x05\xf0N66\xf8\xa0\x14\xde8\xed\xd3\xa3\x80\xec\xbc\ +A\xb3\xae\x13^\xdd\xbc\xf5\xd3\xe3\xcevd\xbex7\ +\xbdN\xf0K\xf3x\x83\xd4D\xe5\xb4\x1b\xb3\x1a\x0fz\ +\xf7E)\xfcBN\xca\xc0\x19\xb7F\x0e:\xd6n\x91\ +\xd7\xc6\x83f\x9d\x17\xadW7]\x9eA\xd6\x99b\x7f\ +vnH\xf8te\xbb\xd5w=,\x18\xa7\xc7\xa6^\ +\x0b\x1b;i\x96\x9e\x8f\xa6\xd6-\x96\x8aE-\xf4\xb0\ +\x0f*\x84\xc9\xa6\x9d\xeb\x9cr^\xd7\x8b\x19\x1a\xf8b\ +\xda\x8b\x0c\xe2\x87\xb3\xd7\xe7mo\x13\x0c\xce&~\x8e\ +b\xedv\xefP\x97\xe0\xd6\x9d\xe9\xcd\x1e\xad\xe9\x17\xa9\ +\xe290\xf8:\x81^\xfe\xbf-\xee\xcd\xcd\x87\x13\xde\ +\x19\x0d\x8e>\xb9\xaei\xd4\x97\x98\x96\xbf\xbd\xc3\x9c\xe1\ +5\x8fh\x13\x979\x83\x0e\xfd\xafo\x8dQ\xea\x84\xdd\ +\x87\xb8M\xcf\x1bo~\xbc\xb4\xd3\x91\x9e\x83\x17=\x99\ +`n\x17{\x7f\xcf\xf5\xa8-\x8f'\xde]f\xb3\x9c\ +11G\xb9\xed\xb4/\x1f;\xd9\x0dv\xea\xd3J%\ +&s\xc8\xa9V\xcb\x8c\x89,\xb5\xf5\xf6*kR\x9b\ +\xef\xf7&:\xd6\x98\x90\xcd\x99\xdf\xb5\x99\xaa\xbf\xc6\x14\ +\xfb\x16\xed\xec\x16Y\xb9X|f\x9c6\x09\xe9\xd3\xc1\ +N\xc5\xa9\x8f\xe5\xed}\xdc\x1a\x89\x89J\xde\xd1c\xdd\ +\x0e6L\xd4\xd2X\xe4\xa6n\xa5\x87^\x7fi\xd1\xd0\ +\x93f\x1b\x8f)\x9bF?\xf3\x1e\xcb\xd6m\xf0j=\ +;\xf1\xfd\x22\x9f\xf3\x9d\x98wW\xe5\xa6F\xa4\x1et\ +z\xc2^xs\xc6\xee\xa8\xd7*1+\xb9\x83\x96x\ +^\xdc=E\x97`/\x09\xea\x1a\x91\xba\xdb\xc9\xb0\xd7\ +\xc4\xa7\x87\xe6\xde\xf4!B\xdd\xa3\x9b\xfc5\xd9=\xd1\ +\x7f\xfad\xe2\x87\xa3\xbaYD\xea\x0e\xa7K\x11\x93\x93\ +\x991w\x1d\x99l\xeb\xe8\xe8{\x8bMZ\x18\x0c\xef\ +\xdfTs\x94K\x81\xde%\xdd\x1a\xce\x1b]\x5c\x1f/\ +\xfep\xe6\xcd\xe7\x1d\x86\xb7\x08\xdb\x5c\x03k\x9f\x86\x86\ +>J\x97\x163f\x12\xedM\xf6M\xbc9\xcfu\xf4\ +\xbac\xb9\xf9jw\x0fu\xb0k\x15\xb9y%\xd7k\ +\x15\xc95y\x9bk\xd43\xa8]~#'7\xbb\xba\ +\xfa\xb3RL\x0e\xd5%\xec>\x9e\xe9\x14\xb6\x7f\xe8\x00\ +5\xcd\xa6K<\x0bR_v\x9c\xdf\x84\xf8\xb6\xca\x0c\ +\xd1\xa9z\xfb\xf4\xddj\xee\xbcy\xee\x9d\x82\xa7F\xb4\ +6h1\xf1\xa0\xd7\xd3\xd6\xca\xa6\xb33\x1d\x86\xf8G\ +\x0e\xfaoG\xd7u'y\xa6~\x8d\x82U~\xd6o\ +\xb0\xefb\xa7\x83\xec9~\x84y\xa6\xebc\xb3\x11o\ +\x7fj(\x99F'_\x18\xe9\xef3\xe8\xbfK\x9d\x02\ +-\x83.LRg\xaeqh\xb1\x86}\xda\xf2\xf01\ +U\x9dC\x9dZ\x87\xed\xd8z\xfc\xaf:y\x9a\xb5\xba\ +\xc5\x9e\x0b\x0fX?(\xebvN\xe6\x84\xfaa\xban\ +=V\xe6\x9b\x04\x8dJ\xd1?\x196g\x95\x9d\x86'\ ++ b\xf9\xf6\x7fB\x88\xd0\xda\x0ei\xb3\x88\x1f-\ +\xb7\x98E\xb8\xb7Z_\xc7\xa6\xe0\xaf\xba=\xbe\x9e\x9b\ +\xa7\xa6Y\xb7GB{\xfb@rJ\xeb!\x9a\xcf\x02\ +\x9f\xc4\xed\xc9\xee\xdbj\x7f\xefa\xad\xd6\xb8u\xde\x18\ +e\xb3*\xf4\xad\x7f\xed5u\x0c-\x19uF\x1e\xde\ +{\xf9\xafZ\xdd\xe6\x9c\xfe\xb8\xe7\x80\x01\xc7i\xebq\ +\xcd\xba\xa9\xbe5#\x93\xa2L\x98\xc3~\x04\xab\xf5\xef\ +\xe2{\xf0\xe1'\xcf\x0e\xb3\xda\xac1\xf2=8\xb8\xd7\ +\x01\xcf\xcc\xbf=F\x84\xb4\x9d\xd6d\x1a\xa7\xa3qG\ +\xb3^\xff\x8b2_\xaenYOoH\xab\xff\xd8\xc3\ +\xd3\xcek\xfd\xc8\x09j\x5c{\xe5\xc8\x7fG\x91\xb7v\ +\xf9\xb9w\x98Q\xf3\xad\xf1\xae\xda\x0c\xab!\xfe6\xb3\ +\xfe\xfb'h\xfd\xee\xa5k\xbe\xdb\xb4\xd9\xd6\xbe\xc1\xe2\ +\x89\xbc\xe4SV7\xae\xbb\x04\x1d\xbco:\xcd,:\ +\xe4Y\x5c\xa3f\xe4\xf5\x87FF/\x8f\xde7\xf9\xa6\ +l\xea\xdab\xd1\xe1N'?\x0e\x1e0\x1aM*\xbc\ +\x81ehp-\x870\xfb\x1e\xc7\xef\x1d\x1b\xf6\x83\xe8\ +t\xb2^L\xc4O\x02mL\x1f\xde|\xf5\x03\x99\xc7\ +\xef\xf4\xdb\xb58\xd5\xd9+\xbb\xc96\xa7\x86\xb7\x08\xb6\ +\xdb\xc8\xef\xdd\xef15^Yu\x1d\xb3\xba\xe0\xaf\xbe\ +W>\xc7{\xfa5m\xda2M\xa7\xaf\x83\x81\xb6e\ +\xe8s\xab\xaeh\xca\xf7\xbfq\xe0\x95\xdb\xfd\xdc/\xdb\ +\x5c;qI\xe3\xc3\xbd\xb3\xa9*\xc1\x06\x11\xee\xd6\xbd\ +\xe6M\x0aL\xb0]\x19\xa2l\xf1\xcaH\xf9\xf4\x89}\ +\xbc)\xceY\xbes-\xdb\x1d_\xfe\xf7\xb8\xd1\x19\xab\ +\xcc~6\x0aNd7\x8b{\xdd\x94\xa2\x9e\x0e\xedg\ +\xac\x08\xb2\x0bZ\xec=={\xf3\xf1.7n[\xfc\ +\x9b\xff9X\xab\xb3V\xd3%!yY\xaa\x8e\xa7\xd7\ +\xd9\x85.o\xa8\xc14s&'9\x10G\xdcoG\ +[\xae\x9e\xdfy~\xcc\xe6\xec\xab\xb1\x8d\xf6\x853>\ +5\xe9\xfbL\xdfc\x96k\xfa\xf1\x05\xfaA\xb9\xb3\x03\ +l.N\x1a\xf7i\xb9\xde\x8f\x9c\xa8@\xe3\xf3\x7f\xad\ +\xde\xec\xfcQ\xab\xbfU\xca\xeb)\xcec\x97[9\x9f\ +\xbe\xb3:\xf0\xc5\x05\xe7F\xa6\xae6\xdb\xdd\x1a\xe6|\ +T\xf3\xe7\x8e\x18}tp\xc8\xf3\x13\xbcK!\xa6\xbe\ +z{\xfc\xf7\xcc\xb5\xb6W\xff\xfa\xba\xa9\xce\xc8v^\ +\x1a\xc1\x13[\x12\x1f\xdcG\xb6\x8cuxD\x0e\xf5\xaf\ +\xf9w\x17B\xbbkD\xf4\x8e{_\x1a\xa1\xa7\x99\xcf\ +\xed\xde\xd2L\xe7\x8d\x8fr\xea)\xd5\xa4\x03\x9dvm\ +\x9e\xac\xaeV\xeby\xf8\xca;\xc3\xfdk\xeen\x5c'\ +\xcfje\x9ef3\xb3\xbeK\x0a2\x16>\xccf\xdc\ +A+\xea\xbc\x5c\xbe\ +\xd9jaV\xcd!l\x8d\x16\xf5\xaf\x9f\xef\x9c\xb4Y\ +\xc3\xd5\x8bXZC\xb9_\x1f\xffu\x91\x99fJ3\ +\xee\x9aeg\xcdoyF9\xbf\xb5+\xb3\xbb\xf9\xd4\ +w\xf3\x8d<\xb7\xec\x1d\x96\xd2\xd6,l\xddn\xcf\x19\ +\xdd{\xdcF\x13\xeb\xfb\xe8\xf8\x8a\xa5\x89^\x06\x015\ +\x0e9\x04\xb48\xd3f\xe2\xf7\xb7\xedU\xee?\x8b\x9b\ +\xf2YoV\x0b?O\x1b\xc2J?|]K\xae\x17\ +\x22L+^J\xd3\x97[\x98\xf1f\x84\xe7\xdd\xe0!\ +\xfa\x08\x95\xce\x0fI\x8e\xf2\xd8+\xbeQ\xddN\xe7f\ +\xdc\xfc\xd0\x95\x810\xbc\xcf\xc5iV\x03t0\xc3\xb2\ +\xe7\x8d\x88\xaes\xd9|-1\xe95\xd9\xc3\xf1\xda\xbe\ +!^\xc6\xf5L\xb7\x0e\xfb\xc1Lx\xab>\xad\x19\xb1\ +z\xcc\x8d7\x13\x8fN\x9e\xadN\x10\x06\xef\xebz\xef\ +\xeab\xfc\xc3E\xd3\xfb\x1fB\xfb\xfd\xfc[Sv\xf5\ +\xe9\xe5\xb9\xae\xbd\xfe\x93\x8d\xa63\xd6\xb6\xab\x81\x84B\ +o5\xefYw.\x05\xd5\xf7\xfcR;\xed~\xe3\xf1\ +\xddf\xd5b\x8cT\x0e\xbe\xc23\x09\x7fg\xc6\x89_\ +z\xd3\xb5\xd1\xeb[\x91\xdfW2Vg\x0e\xa8y\xfb\ +\xac\xca\xde\x17\xdf\xb4\xfdwz~Q\x22|:\xde\x7f\ +lo\xa9\xc1x\xaa\x14\xfc\x82\xe7p\xce.o\xb3\xbd\ +\xb3\xcb\x93u3\xd9*6J-k|2\xd6]\xfa\ +/a\xecN.\x1f\x17\xf8wp\xc7\xfb\xff\xf9u\xab\ +\xd1!\xc0\x0b\xfd\xc2\x95\xec1k\xbe\xcb\xacU\x17\x06\ +4\xf0\x990ud\xfc\xd2\x85\x87\x16\xddn\xb2f\xc8\ +\x9e#\xab\x17\xed\xac\xdd\xa1`JO\xf4%\xdb\x8b\xb6\ +\xea\xc1\xef<\xc3\x13\x0f=\xb9\xb4\xc2*\x81u\x92S\ ++\xe8f\x8d\xcb\xe3\xc7|\xfd/\xd6z\x9b\xab\xf1\x1b\ +\xc4/B\xef.\x9a8\xf7\xc6\xf4\xae\xd3\xea\x13\xab-\ +\xdd\x16\xbf\xd5\xb1oq1g\x14a\xfe\xbc\xd1\x9c\xd0\ +\xae\x7f\xbf\x0e\xb28jm\x9c\x10\x10lK\xae\xecR\ +\xcf@\x97}{\xf0\xb2s\x93o<\xd8\xfa!mn\ +;O\x0e{\xdf\x12\xf8\xde\x95\x99]\xcf\x91\x1a\x8bf\ +\xec\xbdz%\xb5\xdd\xcdv\x8b\xae\x9d\xfa:\xfa\xc8?\ +\xf1\x81\x1f\x1c\xbe\x7fIdwj\x93\xb0&s\xc6j\ +\x8d\x9c[\xe6?\xe6Y\xbc\xecg\xb0\xf5^\xee\xe1M\ +\xc6\xeb{\xc7\xe7\xd5\x1d\xea\xb5\x98a|\x99\x5c\x8e\xb8\ +\xa1f-\xbf5\xdb\xf4]vG\x1e\xfb\xf7S\xe8\xb3\ +\xb8\xee\x9b&\xf6\xab\x93s+.\xe3\xa2\xe3\x08\xe7\x95\ +\x93\xdak\xa5\xc5\xbe\xf81\xe7DP\xc1\x10\xff\xb6u\ +\xaf]V7W\xbb\xc1&U\xdf\xf8\xd6\xf4L\xf0\xe7\ +\x9dq\xbd\x92ek?2,`r\xaf\x03!\xdf8\ +m\xda$\xf4\xe8\x12\x9e\xfc(~\x22\xc3\xdd\xc4q\x80\ +\xf2g\xfbG{\xd4\x8e|\xf9rs\xe5?\xef\x92z\ +\xbfWWIq.\xb8\x98\xcd\x1e\xf3b\xf9\x5c\x8e\xc1\ +\xc2\xa4]&\x88\xb1\xbal\xff\xa7_A\xce\xd8\xd6\xd3\ +\xdb\xbdq\xaa{\xb3\xe7\xa5\xf8\x09\xcf\xb2\x08\xef\x1b\xa4\ +\x09\xf7\xb8\xdf\xc2\x84\x8bw\x1b\x11\xe3\xe6\xf5\x0a_\x82\ +\xb8\xbd\xb1Cn\xdd\x17\xd1v_\x9d^~C3\xfa\ +\xd9\x22\xf29\xa7\x11s`\x01\xc9\xcc7\xab\xdd\xdev\ +\xf1No\xc4k_|\x19\x13\xfb62z\xc4\xd5H\ +\xe7\xad\xc7\xbb\xe4\x0c>n\xd3%q\xee\x12\x02\x11\xff\ +G\x7f\xc2\x93\xb5\xfe\xd0?K'\xbb\xd6\xcb\x8a\xeb\xca\ +hp\xa3\xc9\x89\xc0\x93\x13\xfcgX\xfd\x9c\x14\xbcO\ +c\xd9\xd1/J\xb7s\xd2:\xb6I\xf0\xed`\xb2\xea\ +\xd1\xa5\xce\x8e\x8936\xfb-\x1e?\xba\xa3\xb3e\xff\ +\x96\x8f\x1e\xce\x083\xde\xf8x\xf1(\x8b\xb1\x8dv\xff\ +Pz\xdb\x89g\xb4\x94\x17t$\xd1\x8c0Ug\xb8\ +\xa4n\x9d\xa2M.V~\xbd\xf3\xe3\x88+O\xf5\x92\ +,V|\xeaY\xef\xd0\x95u\xaf\x1a9,\x8b{2\ +H;\x90\xe4\x05mp\xb0\x5c\xb0\x22 \xb6\xdf\xc9\xc9\ +\x8d\xdf\xd7\xd2;\x15\xe5[sd\xab5i\xef}Y\ +#\xb6f\x9f|\xd52b\xb0\xc7v\xaf\x96#\xb6\x7f\ +\xabW?\xec$g\xb8\xd7+\xef\xd5\xadr\xc3\x1a\xf0\ +\x8e}\xb7\xf7J$\x9b~?\x14io\xd4\xd6v\x9c\ +Wo\xd7\xcdHrd\xae\x89\x8ey\xf1\xe3/\xf7\xb7\ +u\x17\x05L\xd6{\xe6\xbbi\xb2A/\xb7\x99:5\ +\xd1~\x9fH\xca\x99\x17\xb39h\xae\x8a\x0f\xbb\xd3I\ +t\xa4\x1b\x10[4\x12\xee\x84\xbf\x1c7i\xed\xa0O\ +c~\x8e\xaa7\xb5M\x04\xbb\xd6\x04\xaf\x88\x87aM\ +\x9b.\x99GD\xce\xbb\xf2\x83\xb1\xd3z\xa3\xf9d2\ +Z\xff\xe6\xe0#]\xea\xf6\xcc5\xdcy8L\xb7\xd5\ +\xfe\x80\xdd\xd3\x82[&\x7f\x08\x09\x22L\x8fjZM\ +h\x8f\x94\xc6\xb6S\xb4j\x866\xfc\x1a\xd6\xe0\xad\xc6\ +\xf5wo|\xff\x193\xd8>\x7f]\x8fh\xed\xb3l\ +\x8fFJc\x16\xab\xb4\xd5%\xb6D\x1c\x9d\xc9c\xd4\ +\xf7l\xf2|Y\xd7\xa1G\x1b\xb0u\xb9\xf1K\xbd\xce\ +\xf6\x9e\xe3\xfdj\xf1\xa4\xda\x8c\x0b>J:\x0d\x88\xd5\ +K\xff\xd3arW\xf7\xf4=\xff\xa5\x85\xb6\xe5\x84\xb9\ +a>\x0d\xa632\xa6\x0e\x1f\xff\xc6\xf2\xafP\xfb\x80\ +\xe9\xce\xef7&\xf4\x18\x10\xc7\xaa\xd1\xe2\x8c\xf2\x93\xab\ +\xea\xe6\xc4\xc1\xf1\x96;\x8dr>\xbeY\xb89\xf8\x00\ ++9b\xf0=D`\xaa\xcc\x06\xad\xf7\x07$\xf9\xf6\ +\x9e\xd6\xc2\xcfq\xc6D\x87\x9d\x9d_\xea&Y\xf4o\ +\x15\xe9\xb6\xccs/c\x5c(\xa2\x7fD\x0c\xc3\x1b;\ +j\x1bu9\x1e\xd6y\xe0a\x9b+A\x93\xdf\x8f\x1e\ +\x18\xf9\x99\xd8\xf3\xb8FT\xb3\xbb\x7f\xeb1u\xf3\xb3\ +Ng\xcdo\xbb\x93az\xe5\x96\xff\xdd\x9d+b\x0d\ +j\xee\xbag\x8a\x04\xc4\xe3\xec6\x0b\xba\xc6}\xed\x91\ +\xd0\xd0B\xc5\x88x\xdc\xc0m\x06\xc3\xb0\xaf\xf7$'\ +\x86\xe9)\xa4\x02<\xfc\xc69\xf4\x8e\xd5\xd4\xa0\xcd\xc5\ +\xad\xe8\x17\xcd?\xd76\xce\xbd\xc8\xa9\x1f?\xb7\x0e\x91\ +Q\xc7\xc2Q\xdbo\x0as\x87\xf2F\xf4\xa1a\xd8\x14\ +\xe6\x8aE\x97Fh\x11\xdf\xda!\xfa=\xdbU\xe9\xd2\ +M\xa5\xc8\xa6.\x9ai?\x12\xc7\xef\x8b\xea\xb6\xda\xa7\ +\xf9\xfa\xcf\xeb\x0f\xfd\xe5\xe9d06\xcfe\xdd\x80\xf0\ +L\x86y\xd2\xc8\xb6\xfd\xaf\x9b$\xce\x0f=\xefS\x7f\ +\xac\xfa\xa5\xd5W\x1c\x13\x02\x88\xfd\x13\xbb\xe6\x9e\x9a\xef\ +\x16}w\xe1\xf0\xcf[&\xf7\x8e\xba\x97\xc9\x08_9\ +\xb3\xcd\xbe]\xa3\x07\x0e\x0b\xfd:\xfb\xdb\xf4\xd9\x86^\ +ji\x1b\x88avZ]w.\xe3\x8d\x1c\xd1jM\ +\x07\x93\xc0K:./V\xc1o\xb3I\xaf/\xef\x8f\ +\xe4\x18tk\xaa\xd9\xf3\xfc\x0bc\xe6\x05eS\xeb1\ +ow?\x1f}\xf1\xfa\xcf\xe8\xff\xa6\xcf\xd9\xb7\xb7\xd7\ +\x9b1'\xf7\xd7\xdc\xcb\xd6ws\x1d\xd5rWd\xc2\ +\xe9\x88\xe9\xc4X5\xe6$\xd2a\xf7s\x87\xd6n]\ +{^[AL^\xa0\xd4G\x97\x18\xba\xa5\xdf\xe6\xc3\ +:\xdc\xa9['\xb57u9\x8a\xfe\xc84\xeb\xf6\xb3\ +m{\x87]\xf2\xeb\xef\xd6\xd8\x8b\xf73\xf9\xe5\xfd\xd7\ +\x0c\xfd7u&\xae\xda6\xad\xf3\xba\xe6\x91J\xe3\xe6\ +\x1b\xeee\x98w\xadG\x5c\x1a\xbc.d\xdc\xe2S\xf5\ +\x88\xc9\xec9\xad\x1e\xb1<\xbb\xf4\xd5%\xea\x1b+\x9b\ +\x12FV\x9b\xcc\x88\x16\xadm\xfdf\x84\x12\xfa\x19F\ +\xaa\xcc\xe7_l7\x84o\x8f\xbcOx\x1f\x8dR;\ +9\xacc\x1d\xa2\x85\xc6<\xe2\xdd(\x97n1\x83\x08\ +\xe5\xe0\xd5}g\xae7\xad=\x87\xd0\x5c\xab\xa5\xcc\xec\ +3\xf6fH\xaf\xa4\x07\xe8OG|\xec\xbfo\xc8\xdc\ +yZ\x17\xedj\xeeX\xdb\x8bh\xd5\xac\xc6\xf8\xc5\xbd\ +\xdb\xd6\xdf\xd0b\xd2\xbeG{\xfbr-\x0e\x1e9\x90\ +k\xbdr\xe2\xe0Y\x0e\xfa\xcf\xd0\x147v$n\x0e\ +S\xc9\xd0KRz|`\xba\xcb\x85\x88\xf3{g\xe5\ +\xee\x1b\xa7\xefy\xbd\x9d\xf3\x05e\xfd\xc0v7:E\ +\xb3\x9e\x8fq\x19\xd6\xf7\x90\xe7\x93!\xad\xd0\xb4/>\ +\xef\xb9~sN\x0b7\x8d\xe17C'\xadm\xf3\x00\ +=\xc3\xe5~\x92\x92G\xffK\xad\xcf?i\xa8\x1f\x93\ +Nh\xf6\xd66\xb4a\xde`\xd4\xde[{\xeed6\ +\xc9|\xa4L\xec\x1d\xf9\x15\xe9\x19?}S\xd6\x0e\xd4\ +{\xbaA\xd5\xd0B=!\x9f\xd8\x9b\xb8\xf3\xe4\xa4\xff\ +\xc6\x1a_\xad\xad\xbaanGb\xf2y\x82\xa1J\xd4\ +\xbf:_\xc9\xdc\xdbw\xcb\x1eUu\xed$\x8b\xbf\xd7\ +[LVE\xbff\xbe\xbb\xa7\xc9L:\x1c\xceza\ +g\xb82\xf9\xf5Q\x1de\xd3\xd6\xfb\xf5B\xe3'\xaa\ +\xb9G\xdf5@\x8a\xe1)W^W\xdb~D\xab\x06\ +=\xb5-\xbf\x9f\xd5g\xec\xbf\xe7\x19A\xe8\x07\x13\x84\ +~@g\x0e:&?}S\xdb!-\xb0%\xd7\x9a\ +\xa1\xff>\xbe\xc3\x16\x06\x11\xb3\xc5\xdcpO\x96\xaf\xf5\ +h\xe6.\xd5\xf53\x1e\xaa\xce~}\xf4\x84\xf5\xb6\xbd\ +\xc8\xea\x7f\xd6\xc1r\xe7]\xde\xbbq\xc7\xb3Z\xa7\xd5\ +\x09[\xea5=^M\x8bX\xbb\xbfy\xf0\x14f_\ +\xa4M\xec\xe8\xb7\xbb/\xf7x\xd2\xae\xf3\x0dU\x99c\ +\xd8!s\xda\x07O\xbf\xc7\x1c\xcb\xd1~\xd9\xc1r\xf8\ +\xec\xad\x1aF\x84M\x84\xde\x8ba\x0e\xed\x17\xd6\xe8`\ +\x93oc\x9a\x95br\xe3\xb6\xd7\xb3\x96\xc1[\xb4\x08\ +\x7f\x9b6\x06\xfd\x1a!]jo\xd6|+\xf7a\x1e\ +\xb5\xba\xc4\x06\x04\xd9\xa8\xdf\xd0Q5e\xfc\xd4X\x8c\ +\x14\xef\x91\x17zv\x5ct\xab\xf7\xb9m\xee;\xf5\xbf\ +\xdc\xef\xb0\x8d1\xcet\x8b\xc6\xe2e\x1e\xbb\x947\xb5\ +\xf1\xb7\xe9\xa5\x7f\x97\xdct\xe9\xb9\x03\x93\x91v\x0a1\ +\xc0\xb0\xb5\xef5k\xaan\x18\xf1\xe9\xda'\xfd\xfaK\ +\xea\xeb\xe5)3\x1f\x05-\x1b\xd1\xf8L\x07U\xd3\xbf\ +\xfe\xeewy\xa3\xa5I\xe8\xdd\xbdd\x5c\xaf\xcf\xb9\x87\ +w;\x99\xac\xf0\xf3\xbfk\xd0\xef\xd6\xa4Z\xca\xa7\x1f\ +\x7f\x9a0e\xbbZ\xf7\xb9\x03-\xe2FO5\x08\xe8\ +\xban\xd0\xf6\x7f]\x86\xabX\xb6u1\x22F\xdc\xce\ +\x1d\xb5K#\xb9`d\xff\xd6w\x1f\x8c\xe9\x1a\xe1\xa0\ +\xd9\x92\xbb\xa4\xcf\x12\xbb\xe5HC\xdc\xbcC\x8bh=\ +\xea\xc5r\xc3.\x8b\xe69\xab\x0d\xeb1\xef\xe4\x7f\xde\ +\xbe\x83\x8fv9\x18\x96\xdf\xb1\xf5\xdd\xa1\xe8\xdbO\x8e\ +\xd8\x9e\x1fb=4\xe4\xb9\xadMv\xdb\x81\xa7k#\ +\xbd;\xc5\xb9\xd9\xbeNC\xbe\xe4em\xb5\xf9+\xe7\ +!\xd1\xf6\xeb\x97eC\x8ef-\xa8\x994\xf6\xe6\xd2\ +\x7fz\x06\xb9G\xa6\x04\xc5\xa3/\x0e[h\xfd\xc4G\ +\x89\xc8\xbe\x1bc8>\xfd\x83ql\x0a\xdaJ\xc3\x09\ +\x17\xff&<\xf2\x07\x1f>\x1f\xd7m\xc5\x93\xcfz\xe6\ +\xc4\xa4\x83/\xbe\x1d\x1ci\xfdU\xfd\xe5{\x86\x85\x0f\ +\x19\x96\xbd\xda\xdd\xd0$\xe6D\x80I0\xf1.\xea\xc1\ +\xb2!\x17\xcf\x9d`\xaei\x1e\x13\xbfJi\xdel\x9f\ +v]?\xccn\xdb/0\xf6\x08\xfc\xb3\xc7\x13\xaf\x8b\ +\xbe\x11\x83\xf3L\x8dbB\xcey\x0e\xed\xeb;7\xdc\ +6:bl\xae\xcb~\xf4D\xd7\xdc\xce\xa1\x84\x07R\ +\xecn\xed\xff\xd8\x93\xf1a\xc7\xbd\xa1S\xf7\xac\x8bc\ +\x9cE[x*\xbaf\xbb\x8f\x19~\xdd\xb2}'\xcc\ +\x1b\xf2\x06\xcd\xe0\xe7\x87\x10\xdf'\xf6\xb7\x91\x98\xe9\xe3\ +\xf7%\xe5\xc3\xd0\xed\x8e\x0c=dCL\xb0\xf4\xbe\x1a\ +\xfeiB\xa3\x03\x99K.\xeb{\xa9(\x9f\x1e\x81\x98\ +\xdd\x88\xd1\xea\x8d\xda_ne\xb9\xa4\xaes\x96\xde\x83\ +\xcc\xa6\xcd\xe3C\x92?\x0c\xcc\xf6\xdf\x8e\x1e\x14i\xce\ +\xb9P\xb7u\xb3\x86\x97\x06-m\xa3\x17rr|\xbe\ +A\xac\xb6\x9d\xde\x9e+\xcdV=\x98\xb0\xe8B]\xce\ +\xdfs\x89\xc8\xc7\xed\x86\x9b %\x1d\xc9\x01\xad\x82\xb3\ +\xa3\xf3kOz\xec\x917\xe6h<\xd2W\x8cx\x07\ +V\x9e\xe7\xee\xe8B,98,%\x06\x09\xfb\x88\x87\ +\x1e#\x8cb\x06.\xf3\xa8\xbb\x93\xccWC\x9b>\xde\ +\x7f)\xd2\x9f\xe3\xaa*\xf7\xcb\xfa\xe1\xd0\xc3\xfar-\xa4T\x0f\ +\x1a0z\xf7\xb2\xb7\xa9\x8f~\xe4\x8e\x5c\xe3\xfa\xec>\ +\xb1(\x1c)acN\xa5\xb5\xbf\xa1\xe2r\xd4\xd9\xb4\ +\xad\x0e\xcb\xa9\xee\xf0\xc3#\xde\xbal\xf7\xf9Z\xc0\xdd\ +\xf2\xa9\xf1+\xa5+}9#\xdf\xbb\xdf\xff\xef\xd4R\ +\x8dh\xff\x94\x95\x0b\x88#\xdf\x9e\x0c\x9a\x9e?x\xc0\ +\xa4 D\xa8\xedUagG\xcd\xadS\xfb\x7f5>\ +-\xb4\xb6\x7f\xfaj\xa7\x9d\xe1\x1c\xe2\xc8c\x0b\xe5A\ +n\x93yK5N\x06\xbe\xbbP_\x95\x196%j\ +\xcd\x0a\xa4\xf7oe\xaa\xdf\x0e\xccP\xaeC\x8cDS\ +\xae\xc3\xd8\x969 ^\x0d\xd91#\xfc\xf5-\x0f \ +\xec$%7|TC\xe7qK\x17\x13\x95;\xeaL\ +r\xc4\xe1\xd0]\xce)\xc4\xc0\xe0\x9e}&\xe43\x02\ +_\xdcP7\xef2ou\xb0E\xe6#K\x9b\xe4\xd8\ +\x19W'\xf1\xfa\xb4$\x1a\xb9\xa9\xc7-\x18R\x13\x1d\ +\xb6\xe1\x8d\xb7\x8c\x08_\xb0<\xe2\xca\x89\x84\xab\xe6\x8c\ +\x18-\xa6\x17\x9a\xfc\xd3.Mw\xd8>D\xa6'R\ +\x05\x1d\x8f>\xb4\xf8y\xf6]G\x15o\x15\xf3\x80\xb0\ +\xfc\xd1H\xa1\x8b\xab\xb3Q\x09\x99M+rr\x5cg\ +\xe9\x9e\xfb\x97 fw:\xec\xf82a\xe0\xc2e\xc9\ +c\x89\xe4\x08\xf7\x8c\x1d\xe6\xc1\xdbR;\xab\xe8\xde\xbc\ +\xe8t\xfc\xc1\x85\x1e3\x03\xfc\xaf\xd6\xbe\xe8b\xfb\xe8\ +\xda\xccN\xb9_\xf4c6\xd9\x5c\xbc\xf3@\xab\xb1\xd5\ +\x93\x9c\xb9\x96\xd7\xfc\xefn\xbb\xe1;q\xd6\x15\x8ei\ +\x7f\xb3\x85D\xcd\xe3G\x9e[\x052G\xfb,M~\ +\xdf\xc6\xe1\x8c\xca\xd7\x1e[\x18\xc17\x89\x01\xce\x83\x07\ +\xaeP\xd35\xfc\xd9*\xd4\xd4\xb5\xc1\xd8\x94k\xc3\xee\ +^\xb9\xa1rzo\xbakw\xa4\xe09X?gn\ +GV\xb2\xf1\xfa\xe3Q>\x8f7\xa5\x1f\xe7\xe8\xeb\x13\ +\xf5j\x18\x22\xf6\xa1\xd2c\x9bF\x80\xf5\x8c\x8e\xbd\x9f\ +u\x9c\xbf\x02-\x7fj\xf2\x97y\xfb#G\xdc\xf9\xaa\ +E4\xd4PR\x0a\x9e\xf83b\xdf\x82\x05+\x9a\xba\ +\xda\x05\xecF6\xf4q\xafnGf<\x89\xe3|\xee\ +\x01\x8ap{\x87\xc5c\xd5\xc9q:\xc4\x8d\x08\xf7s\ +\xb9\x8b?+\xa9\xde\xb3\x9f\x12\x95k\x85\x9e\xd3)\xe0\ +K\xf4\xfaUwn\xab\x87\xab\xc4\xac\xf9Y\x7f\xc2b\ +\xc4\xff\x0f\x8fU\x03=\xf7\xef\x8fK\x8f7\xdf\xf7\xe9\ +^\xe0\xc2\xe3\xb3f\x84~tr\xb8\xf2\xa0\xf7!\x86\ +\x97z\xda,\x820E[\xb4\x860\x8bpw\xcb\xd8\ +\xc4\xd0C\xa2\xa1K\xf7\xc8\xef\xef\xbblB{\xfci\ +\xfd\xa1\xd8\xcfw\xbb?m\x9f\xbe\xdbA\xdb\xe1q\xbc\ +uk_\x15W%\xcd\x03\x9d\xda\xb9\x1c~\xf1\xcd\xa8\ +\xe7\xd5\xcf\xd9>\x13W\xd7\xf3\xb7\x9e\x911\x17)\xd9\ +G\xfe\xfdt\x1f\xbd!):j\xe1\xa5<5\xf7\xe9\ +\x84\x1da\xef\xd2\xa9\xdd\x9b6Zis\xdc\xc8\xd3_\ +\xf7|2<\xf4\xe2[V\xcbg\xb7\xee\xe4\x05\xef~\ +\xcf\xbbY?u\x9a\x11o\xdcuu\xc2\xbbi\x8c\xcd\ +\xbeq\x0d\xd0\xcbu\xd60/\x9e\xf1\x8ex\xd9q~\ +\xcf\xbc\xc5\xbbs\x8f\x91\xa6\xf9\x9d\x08\x82C\xc4\x9c\xb7\ +\xd9~\xb1\x1fb0G\x8e4\xf5\x9d\xfd\xbe\x8b#\xb2\x01\xbe\xcf\ +\x9a\x9f>\xb7\xddS\xfb\xc0n\xf6m\xb3C\xac;2\ +;Yu\x0fvq6\xfdQ\xab\x07\xd2\x8dW[]\ +\xf8\xdc\xb56\x9a\xe5\x07\x86\xdb\xd55\xd3b\x93\x0f\xe8\ +q{\x1cLV\xc2\xeb_H,t\x1b9\xfa\xad\xba\ +\xea\x86\xfc\x90\xfe{T785\x8b\x1ap/om\ +_\xe7\x11\x81\x88\x16\xde\x98\xacI\x8f0^t\xd0\xc5\ +\xec\xfekD1\x09\x0fM.G\xaa\x10>mB\x9a\ +\xfc\xdc\x7f \xdby\x87\xdf\xec\xf8\xcb\x0dk^~7\ +\xa2\xe0\xca'\x87\xb6\x1f\x95\x08c\xada\xdf\x94\xf4\xea\ +\xf0\x9a\x8c\xe8\xab>.\xa9\xb7\xe6\xbe\x03\x93/\x87\x14\ +\xa8\x04+[\x85\x8ckqaD\x7f\xcf\x90\xf9\x93\xeb\ +0]l\x87\xd6^\xa6\xa2\xd9\xf3\xcd\x9au\xba\x9d<\ +\x8f\x0d\x8f5~W[\xdf\xfaXC\x1f\xff\x19\xaf\xee\ +2\x82\xa7\x10\xfbZ&\xaf\xcfU\xcb9\xaa\xd2\xf6A\ +\x13F\x8bGm{g\xcc\xf68\xf6/s\xc0<\xec\ +\x0c\x9c\xb0\xca\xcc\xcb_\x85\xb0Z\xa5\xbfO\xf9\xe0\xcc\ +\xec\xa9#\xbc:\x12\xc4\xed\xb6\xdc\x14'\x8f\xb3\xc7\x12\ +\x17\x8df\x9c6\x19e5\x92\xad[\x7f\xfcp\xdf\x1d\ +zy\xef\xc7\x8e6#\xe08L%\xec\x22R\x0f9\ +e4\x9a\x12\xa7K^\x8a\xef\x1c\xf9Z\xc5hf\x8d\ +(U\xcd\x8b-\xb6\xf4\x0aHX\xa5\xc2\xbc\xeb\xa5\x19\ +\xa04h\xc9\xed\xc9\xb7\xdfL\xed\x98\x98\xa8\xa4\xd5k\ +\xdeR\x13%\xadC\xf6\xb9\x83\x9auGH\xcb\xbb~\ +*\xe8\xdd\xb0\xc6\xc1V\x7f\xf5\x99\xb8w\xd8\x13%\xed\ +\x13G\x97\xb6%\xb2\xdc\xb7\xeah\xe8_\x9f];\xf8\ +\xe1\x92C\x05S\x22\xd2\xea\xed[\x17\xed\xc8RvJ\ +Zu\xed\x8b\xbdC\xf3\x89\xb7\x9c\xcc\xb6\xaf\x19\xb5\xb1\ +\xb9\xe9\x7f\x87w\xae;\xb9\xf4\xc8\xe2\xf5\x83\xae>\xe8\ +\xdd\xcc\xdc\xf5\xb9\x9a\x93\xc7\x1c\x8d,\xff\x05\xb5'\xf6\ +\xd8>{\xfb\x9a\x995\x062\x1f\x1bjd\xf5Z\xa0\ +\xfdz\xecv\xf3\x9a\x9a\xff\xde\xcfz\xa21M\x93 \ +\xd0\xef\xff;4\xc9>\xf8,Ah)\x0djs\xed\ +r\x86r#U\x22XS\x7f\xc9^w\x17=oc\ +\x82\xb9\xa1\xa6\xd5\x8e\xbd\x1e\xdd\x1b{]\xe10\xeb2\ +\x88o\x17j\x06\xd5\x98Z\xa7~\xb2\x81J\xcc\xc8\xae\ +\x17\xd8\x86\xd7\x92//\xb2\x8b\xbd\x9f\x10sCyP\ +|\x07\x22\xef\xd3\xe5\xc1\xfd\xdexg{\xdb\xda\xfd\x8c\ +K \x96\xadw\x1cT\xaf\x8b\x8aWF\xe7w\xf9g\ +\xeb\xf6\xad\xf7\xc9\x09{\xbcG\x13\xc9\xb7\x82\x8c\xf7\xf5\ +\x9a\x10~*a\xcfG\xee}\xbf\x99c\x10Q\x9e\xee\ +z\xeb\xadZL\xbf\xdb\x81Zk_+\x8dZ\xe7q\ +\xa1Y\x1c\xc3\xfc\x87\xb3\x97\x9d\xb2W7\xd3o\x7f\xfb\ +\xa2\xfd\x8d\x1e\xd6\xc8\xf4(A\x80\xdf\xbc\xb1\xcf\xdb\xe0\ +&?\xafk\xfe\xfb\xa3\x9dO\x00\xef\xbaM\xff\x83\xb5\ +\x01\x1d\x16Z\xc1\xc6\xb6u\x9a\xf8=\xfd\x1f\xb3K\xef\ +\xa1y\xb9\xe7\xfe#\xb4\xb2,\xefE\xc5\xe87\xef9\ +\xa3\xf6\x87\xfe'\xa3\x875v;\x12\xc1 \x08\x1c\xc3\ +\xe8bT\xf3\xf1\xda\x09\xe1c\xde\xec\xee\xe1oqx\ +\xf2A\x0d\xc2\xb1Y\x8d\xc6\xa7U\xfa\x1f\xb6Y\xebd\ +8m\xeb\x94t=\x8f\xe9\xe9uw\xd7b\x0e`k\ +\xa1\xa7\x987\xbf\x18\xdf\xce\xe7<\xef\xa0M\xffK\xf1\ +\x8f\x09\xa3\x1f7T\x1b\x13\x1bTn\xd5\x1e\x16\xfa?\ +\xa6\xde\xe9\xcf\xc9\x87\xdd\xd5'\xb6\x1f\xaaf\xda\xdc\xae\ +\xff\xab\xa9\xe1\xf5\xda\xfd\xa4\xc2\x16>\xf3\x03L\x86u\ +\x8c\xe9\xb2s\xa9\xd2\xe9\xbd_\xfe\xa7\xa5j\xa5=\xbd\ +\xc7\x193\xffQ\xdf\x16\xb5[\xf4\xbc\xe0\xdfE\x17\xd2\ +:\x8cl\xfc\xb8\xc3\x95:\xcc\xb9\xebX\xa75\x82\x0d\ +\xd8W\xed\xcc\xdb\x8e[\xdcn\xd1\xd3\x95\x8d\x09N\xe3\ +\x0f\xdb\x03\xd4#\xb6\x5c\xdfa\xa0t\xba\xa1\xdd\x943\ +\x1a\xd35\xb3~\x9a\xf0j\xd4Q\xbd:\xac\xbfg\x0c\ +s\xca\xfb\x89\xe1\x86\xebG\xf8\x9b\xaf~\xa2F\xfc\xb5\ +\xf65\xa9\xdc\xc0\xa2\x87\x91\x96\xb6\xdfr\x08[\x0d\x1f\ +\x08\x1c\x11\ +\xe8\x15\xd5\xf2\xbe\ +\xeaA:\x8d\xbbr\xdb\x05\x02\xf8\x07\xbb\xa2Z\xcf\xaf\ +\xba\x10K\xe3Pb\xfc\x0b\xe0^\x8fUm\xdf\xff\x0e\ +\x10\xc2\x12\xf0\x11I\x88{\xf0+\xeeV\x80\xb9W\x83\ +|`7K\xc0W,\x01\xfe\xc1\xb7\x5c\xed\xd3\xfd}\ + \x85\xc6\xa9X\xfc\x0b\xe0\x1ebK~\x0a0\xe7j\ +\x90/\xf8\xb1\x04\xe2\x86\xa5\xe0\x1f\xe2\x8b\xd5\xb6\xde\xef\ +\x07\xf94nK\xe0_\x00\xf7\x90_\x10\xaa\x00s\xad\ +\x86\x8a\x81P\x96@\x0e\x89\x08\xfc\xcfb\xfdI\xb9\x1b\ +\xcbu\x11\xe8\x90,\xcb\xa64h\x93,\x0bm\xea\xff\ +\xad\xf5\x114'Y+\xf4\x05~O\xff\x9b\xa5\x0e\xf5\ +=\xf8~e\xaf\xa1|\x00\xb85\x13\x83\x7f\xc81\xbb\ +\xa5\x00s\xfc\x05\xf8Fx\x5c\xa1G&\xad\xed@&\ +o\xecI\xa6\xed\x9fHf\x9cYJf^\xb6#\xb3\ +o\xed\x22\xb3\xfd\x0f\x90\xb9\x0f\xce\x91\xb9\xa1\xee\xe8\xe7\ +Y2\xdbo\x1f\xfa\xbd3\x99yi\x1d\x99\xe1\xba\x88\ +L\xdd3\x86Lfv'\x93l\xdbS\xcf\x85\xe7\xc1\ +s\xad\xaa\x04=\xf8\xd0\xb8\x16>\xfb\x90g\xf8\x1b\xe6\ +\xeb\xe9\xd2\xe7U\x17\xe3+u\xe702\xf3\xe2\x1a2\ +\xe7\xbe+\xc9\xfe\x18JrS\xbe\x91\xbc\x9c4\x92\xc7\ +\xce#I\x1e\x8f,up\xb9\xe8\xefrI^v*\ +\xc9I\x8a!\xd9\xefC\xc8\x9c\xa0cd\xc69K2\ +e\xdb\x002i\xb5\x01\xcd\x17\x14\x9a\x16\x92i\x5c\x0b\ +\xe7\xf28*\xc0\xdc\xe4\x07p\xd6\x11\xafNZ\xd5\x86\ +L\xdd=\x86\xcc\xbe\xb9\x13\xe3\x8b\x9b\xc1Bx\xe4\x94\ +\x8e\xe7r\x0e^A>\xc9M\xfdN\xe6G\xdc&\xb3\ +\xbc\xec\xc9\x14\xa7Ad\xd2\xca\x96\x94\xacPL\x19\xe1\ +(\x84{\xb0\x0b\x1e*\xc0\xbc\xe4\x83wt\xfe\x92\xed\ +\xfe\x87\xce\xa5\x05\x99\xff\xea\x16\xc9\xcdL\x92+\xbeK\ +\x1d\x88G\x00O\xc9{r\x99L?f\x8ee\x0c\x9f\ +\xffT\xfa\xde\x14\xc1CV\xf1\x1cR\xb8o\x90\xa4\x00\ +\xf3\x92\x03\xde\xbb\x229\xbd\x96,\x88~\x86\xcee\xde\ +\xaf\xc3\xbb\x88\xc1\xcb\xcb$\xd9\xef\xee\x91\x19g-(\ +]\x01\xf8\x81b\xc8\x85$\x1a\xe7|\xfc\xc3\x9d\x93\xaa\ +{7\x03\x9d\xaf\xa45m\xd1>/#\xd9_\x9e\x91\ +$\x87]\xa9x\x17\x1e\xc3m9\xf6\xb3\xfc\x8e\x83\xf3\xfd\x1d\xf6C\ +\xffB\x1a\xc8c\x15\xd5\xdd`W>\x8eK\x07\xc0=\ +/+\xb9\xb2\xd1T\xa1\xe3\x17\xd3\x00\x9bUT\x8bD\ +q\xf1\x8f\xe4=\xf0\xfc\xdf\xf5\xdc\x0b\x8f\x82\xf8(2\ +u\xd7\xa8_A\x03\x8a\x8f\x7f\xb4\x07\xa0\xeb\xfdJy\ +\x0f\xf6\x04//\x8b\xe4e\xa7\x90\xdc\xac\x14\x1c\xeb\xe1\ +\xe5e\xffR\x9f\x12\xfbs\x18\x99\xb2\xb9_E\xd3\x80\ +b\xe3\x9f\xb6\xf1*T\xcf\xe7\xf1Hnf2\xf6\x19\ +\xe6>\xba@f\xdd\xd8\x86cy\xe0\xb7O\xdd3\x16\ +\x9f\xc3\xd4}\xe31\xff\xc9<\xbf\x92\xcc\xbe\xb9\x83\xcc\ +{z\x19\xd9\xefo\x10]\xa4U\xdc\xbc\xd0\xc8{q\ +\x9dLZ\xd7\xa9\x22\xe3\x06\x8a\x8b\x7f\x88\xd5\xaei\x87\ +\xed\xfb\x8a\x18\xbc\x9ct2?*\x98\xcc\xf2v\xc4\xbe\ +C\xbc\xcf\xd6-\x04\xf2;\x04r<,u\x8arC\ +\xe0\xe7\xca\x968\xb6\x04r\x1ar\x02\x80>y\xf9\xd9\ +\xf2\x9f$\x97Cf\xfb\xee\xa6rP*\xc6O\xa8\xb8\ +\xf8G\x00~=y\xfbv \x0e\x98\xfb\xd8\x83Ls\ +\xf9\x97L\xb25,\xc2o\xb9\xce\x98nal\x19~\ +&\xaf\xefL\xa6\x9fZ\x80\xfd\xfb 7\xe49xH\ +\xfe\x00\xef\xa9 9\xa0\x98\xf8G\xf8\x00\xbe\xcbI\x8e\ +\x93\xdf>\xb2\xf3\xc8\xfc\xf0\x9bd\xda\x81)\xe8\xfc\xb6\ +\x90o\x5c\x9e\x9fg\x80\xf8U\xfa\xc9\xffpN\x89<\ +\xf3\x0b\x0ab_\x92\xc9L\xe3\x8a\xa0\x01\xc5\xc3?\x9f\ +\xef?\xbf&\xb7\xfd\x03\xdd\x11\xf2\xb6\xe0\xb9\x15\x1a\x7f\ +\xa5\xe9 y\xc3\xff\x90\x1e\xe1D\xe5\x99\xc8e\xf0\xc8\ +\x9c\x80\x83\xb4\x1c\xf8\xcd\xf1\x8f\xce~\xc6\x99er\x8a\ +\xe3\xf1H\xf6\xbb\xfbX\xbeS\xb9\x01\xbf(\xd6\x06\xe7\ +t\x85\x1e\x99~\xc4\x8c,\xf8\x1a!\x87u v\x92\ +\xfe\x13\xd9A\xe3\xe5\xed#V,\xfc\x83,Ez\x15\ +\xd8>2\x0f\x1e\x97\xccE\xbac2\xb3\x07}\xe6+\ +\x87\x96S\xb7\x0f\x22\xf3\xdf\x06\xc9\xbe\x1e4\xf2\x9e]\ +!\x93V\xb5&\xe5\xc8\xbf\x14\x0c\xff:8o\x87\xe4\ +\x14\xc8\x8e\xfb\xb0KdR\xe5\xc5\xd5\x04h\xa0)\x99\ +\xb2\xb1'\xd6\x0de\x1d`o\xa6\x1d\xfaW\x9e\xf4\xac\ +8\xf8\xc7z\xb4\x11\x95\xbb#\xdb.\xe1s\xaf\x10\xb8\ +\x17\xa0k\xec\xc7x\x1f\x223\x0d\xe4=\xbbJ&\xd9\ +\xc8\x8d\x07(\x0e\xfe\x11MC\xfe=\xe4V\xcb2@\ +\xdec\x9e\xaf(\xb8\x17\xa0\x81\xd4\x1dCIN|\x94\ +L\xeb\xe3f%\x93\xa9{\xc7\xc9\x8b\x07(\x08\xfe\x91\ +\xce\xbf\xca\x00\xdbg\xb2\x0c\xd0\xf3\xb1\xaeWY\xf2^\ +\x02\x1aH?1\x0f\xdb\xf4\xb2\x8c\x9c\xc0\xc3X\xbf\xfc\ +m\xf0\x0fg\xc3y\x84L\xf6\x12\xd8\xf7`\xe3)X\ +\x8eu\x09:\x07\x1f#\xe4\xfc\x80\x9c\x92v@\x8c0\ +\xd9\xa1\xbb\xfeA\xef?\xbfR\xea\xd8:\xe4\ +\xd0\xa6\x1f\x9eYu\xce\xbe\x00\xdd\x83\xbe\x22m\x9c\x00\ +\xe2\x97i\x07\xa7\xca\xba\xee\xca\xc7\xbf\x95\x1e\x99\x13|\ +B\xaa=\x80\x0165\xbeW\xa5\xe8r_\x04\xfe\xc1\ +'\xc0\xf9\xf1I\xca\x95\xf3\xc8\xac\xab\x1b\xab6\xfe\xe9\ +\xfb\xd8`\xb3K\xb7\x05h\x0f\xaemV<[_R\ +\xb0\xd6\xc7\xb5\x05\xa4\x1d\xb9\x8f\xce\xcb\xaa\x03T2\xfe\ +up\x0d\x05\xb8G/\x15\xfa\x91\x1d\x9d\xb6gl\xd5\ +\xe3\xfd|(\xf4yIwG\x15\xe2\xcc\xf8n\xb1\xf4\ +\xbc\xafr\xf1\x0f\xf1\x91=cp~\x9d4\xa3 \xf6\ +\x15}w\xa6\x8a\xf1~>\x80\x0c\xd8jJr\xd3~\ +H\xb5~NR\xac\xac~\x80J\xc6\x7fSd\xc7.\ +\x90:\xd6\x0b\xb9a\xf8\xfe\x5cU\xd1\xfbK\xe0_\x17\ +\x9f_\xf6\xc7GR\xad\x1f\xf2\x16Sw\x0e\xaf\xc2\xf8\ +\xd7&3/\xae\x95Z\x07\x86\x5c\xcc*\xcb\xfb\xf9\xb0\ +\xb2\x05\x99\xfb\xf8\xa2T\xeb\xe7\xe5f\xcaj\xfbT.\ +\xfe-\xb41\x0e\xa5\x1a\xc8^\x84|\x5c\x9c\x93Y\xd9\ +8\x94\x05\x10\xee\xb2\xfd\xf7K\x87\x7fv.u\x87\xb8\ +*\xe3\xff\xf6\x1e\xe9\xd6\x9e\x9f\x8ds\xed\xaa\xfc\xf9G\ +\xf4\x0by\xaeR\xc5\x03\x10\xdf\xcc\xbch+\xcb\x19\xa8\ +\xba\xf8\xcf\xcd\x90w.D\xa5\xe1\x1fp(\x95\x0c\xc4\ +\xf8_\xfbg\xe2\x1f\xd9~`;T\xc2\x9d\xe9\x0a\xc0\ +\xbf\x94:\xd0\x9f\x8c\xff\xbcL\xaa\x96\xce\x9f~\xfe/\ +\xfd\xa1\xf8G6\xa3\x9cb\xa0\x95\x0bh\x0fp\xec[\ +\x9a\xc1- 3=VWi\xfcg]\xdf*\xe5\xda\ +e\xd6}\x14\x03\x90\xed\x0e\xf9<\xd2\x0c\xea\x0c,\xa8\ +\xba\xfa?\xf0\xbe\x0b\xab\xa4\xce\xf7\x85\x1a\xbdU\xd6\xf7\ +\x8fA\x17\xe7r\xe6=\xf7\x96\x0e\xff\x10\x03t\x99V\ +\x85\xf1\xdf\x14\xdf\xb3\x95\xf6\xce\x1c\xd4{\xabRq\x7f\ +a\xa0\xef\x0e\x16\xc4\xbd\x92j\xfd\x90/\x97\xe24\xb0\ +\xea\xfa\xff\xe8\x9cX\xf0cJ38?>\x90\xc9\xf6\ +\xdd\xaa\xb4\xff\x1f\xfc\xb7\xd2\xd6\xa6\xe5\xfc\xf8\x88k\x9d\ +V\xd9\xf8\x0f\xd0\xbf}W\x8cGi\x06\xf0\x8d\xb4#\ +U0\xf7\x83\x0fh\xdeR\xeb\xfeh\xc0\xbd\x22|\xa7\ +\xb1\xaa\xe2\x1f\xe4\xdfj\x032?\xc2O\xaa\xf5\xc3\xc8\ +\x09p\xa9|\x8f+5\xfes\xee\x80\xde#\ +3\xed+ \xfe\xab\xe8\x99\x96\x14 \xe7\xcdy8\xc9\ +aI\x97\xf3\x08\x03\xe7}\x1c1\xfb=\xee\xff\x08A\ +\xd2\xea\xb6\x94M\x83\xf7J[\xa06\xd3o@\x13r\ +\xaam#'\xde\xafx\xf8\xb7nN\xd5S\x8b\xbaG\ +\xe6\xdc=\x8a\xefHA\x0d>\xf0q`?\x1f\xbfO\ +\xdf\xf2\xaaK\x13YW\x99\xb2\xd54\x83\x9c\xf7\xeb[\ +\xe5\xc5#+\x06\xff\xfc\x1e{\xe5\xd1M\xf9w\x01\x04\ +s!9l\x1c\xe7\x87\xfb\xae\xe0\xeb\x85Zx\x90\xef\ +\x04\xf7\xc5\x92\x90\xee\xcf\xe2\xf7\xd7*F\x13\x95\x8fc\ +\xd1\xeb\xd3\xa1j\xd8\xcaX\x13\x8a\x9b\x1c\x87\xfb\xcc\xc9\ +)\xee!\x1f\xfc\x0b\xf6TD\x9f!\xa7\x15d\x1c\xf4\ +\xd9\x93\xf8\x9e:\xd8\xc3[L\xca\xac\xf1\x0b\xb9\xf2\xdc\ +\x8cD\xb2 \xe6\x05\xce\xff\x85\xfb\x1f\x10C\x80\xef&\ +\xadmO\xf7\xea\xe4\xd3\x84\x82\xd0\x03\xd4\xb0\xdd?\x09\ +\xfbke\x1d\xd0kP\x8e\xf6\xaet\xf8\x17\xec\x99\x8a\ +e\x9a!\xa2\xc9\x81\xb8njN\xd0Q\xaa\xa7bV\ +2\x99\x1f~\x0b\xcbs\x89\xf0 C,\x08\xbe\x03t\ +\x03\xef\x85\xde:\x99\x977\x90i.S\xc9d\xfb\x7f\ +\xe4U'Av\xdc#\x1e&\xeb\x80\x9er\x10/\x91\ +c\xceS\xf9\xf0O\xf3Y\xd0a\xe0\xbcA\x1fT\xa8\ +K\x07\xfd\xcd\xb8\xe9?J\xc85\xcc\xab\x1c{K\xc6\ +\xab\xd0\xb3\xe1,\xcbe \xbb\x0ah\x22\xf7\x89'\xd5\ +\x8f\xb32\xf4\x04\x9a\xe6\xa1\xde\x07\xe7\xe7g\xb9,+\ +\xe7\xee\x11y\xfb\xba$\xc4?\xe5\xa7\x87\xf3\x09\xf9:\ +\xf9o\xee\xa2\xf3\x16_\xe6\xfdu\x9c\xa3\x0b\xb5K\xcb\ +\xb4St\xb1,\x97w\xad\xdf\x9c{\xa7*\xe7\xfcC\ +/:[C2\xcb{\x93\xdcj@r\x12>P=\ +b\xe4\x9b\xef \x19\xfe\xe98\x1d\xf8\xdb\xcb;p\xfd\ +\xe2\xb2\xe6\x0c2\x04\xe2\xe0H\xa6\xcbm\x94\xea\x1f\xaf\ +\xa8\xfa\x9f\xd4:\xa1\x96\x0d\xd8x\xf2\xaa]\x0c\xcf\xc9\ +\xf4\xdcP\x11\xfa\x8c\xe4\xe7_\xcaX\x15\xf0\x8a2c\ +\x94\xfc\x1a\x10H\xaf\x93\xd7\xc0\xb91H\xee\x96\xe0=\ +\xd0\xf3\x9b\x9f3\x22\x97\xfe{\xba\x85\xf2\x18\xees\x03\ +\xbd\xcb\xb3n1\x0c\xe8\x0f%\xe3=O\x19\xf1\xdfL\ +j\xf9\x0cr\xa2\xa8\xd7\xa1\xf8g\x83]'\xed=X\ +Q\x03\xe7F\x80\xfeWl\xcf(9\x96\xed\xbb\x0b\xdb\ +\xd0)\xdb\xfac\xba.\x9fO\x81_\xfb\x9b\xd2\x7f\xe1\ +y\xa9\xce#q\x7fxN\xc2{\x99j\x18\x89\x5c\x07\ +\xaeiVa\xbd@\xca\x85\x7f\xa87\x01\xe7\xaa<\x03\ +\xdfQBzb\xa9:\x00Z\x1b\x9c\x1by\x0e|f\ +\x84u?~\xad\xa17\x81\xf8o\xb8\xc9_1O\x83\ +\x1c\x0c\xb0U!\x06\x09\xb1H\xfc\x1d\x0bm\xda\xffH\ +\x83\x05m\xdb\xa2gB\xdd\x15\xe8'\x0e}\xbe\xe1=\ +\xb2\xd4\xae)m\x80\x0e\x9by\xdeZ\x0e\ +;\x90\xcc]\x87i#\xd3s=\xf6K\xe6\xdc;\x89\ +{\x89s\xbeGQ5\xfcd\x88\xdf\x949\xd0\x9c\xa0\ +N\x1c\x0b\xf8\x93\x22\xe0\x9f\xaf\xa3\x87]*\xf7R\xd8\ +Q\xc1\xe2u\x00\x9a\xae\xe4a\x1f\xf3\x07\xe8K\xd0\xf7\ +\xbd\x04\xcf\x11\x87\x7fq\x83\xcb\xa5r\xb3*\x12\xcfb\ +F\xde3o\xda\xc7\xaf@\xfd\x7f@\x07@<\xaf\xbc\ +2\xaeT\x1d\x00\xd7\x80\x18+sM\xccb\xefCg\ +\x19t\xf0\x12\xef+/\xfe+i@\xadh\xa8\x11\xa8\ +p\xfd\xbf@\x07\xd87\xa1\xdc}\x8f(\x1d`\xb1h\ +\x1d\x00\xc9V\x88\xf3\xc8\xb3\xb7\x16\xe4\x92%o\xe8\x22\ +9\xffW\xa0\x01\xb8\x87z\xe1\x0a\xd9\xff\x0fx5\xda\ +Wiz\x1a`\xdf\x95\x98gJ{\xffE\xdc\x00\x9d\ +.I\x94\xdcTp\xfc\xffb\xdc\x97\x1f\xff\x00\xd6\xcd\ +\xc9\xdcP\xb7\xb2\x17\x83\xe4&\xf4\xea\x84:\xa7\xb9\x0f\ +\xceQ\xf9\x0a\xd6B\xbeK:\x1e\xce\xd7\xc7\xe55\xb2\ +o\xee\x14\xcdk\x14\x15\xffh\xaf\xf2\x9ezUF\xdd\ +\xf2\xf2\xe3\x1f\xe7\xac\x8b\xb8\xaf\x8ct\x02\x90\xe1\x18\xdf\ +\x88>\xe0o ?\x11\xd7g\x02\xbc\x8b\x8aY@\x1e\ +\x9cC7\x92\x93\xf8En[\x09w\xe22N\x89\xb9\ +\x13\xa7\x80\xf8\x87\x5c\x9el\xbf\xfd\xb8\x1eh%\xdce\ +\xe3\xe3_\xf2\xfe\xcf\xa0\xaf!\xbc\x82_\x1b|\x01\x90\ +\xc3\x086\x01\xe8\x85i{\xc7\xd1\xf8n.YL^\ +J\x9fBi\x03lq\xb1\xf1q\x05\xc3?\xd0}\x86\ +\x9b\x15\x95\xc7P9\xb1j~\xff\xe7r\xf4\x7f\xa7x\ +v\xc6\xd9e\xb8\xff!\xaeA[\x98\x87Q\xce\x1c\x0c\ +\xa8}\xe2e'\xd7=e\x7fyJ\x9f%\xd1\xb6\xa6\ +\x22\xe0\x1f\xfc\x9cy\xe17i\x1b\xa5R\xf3\x98\xf8\xfd\ +\xdfM\x10\xb0$\xff\x9e\xaeP\x8e\x85\xf0\xfcK\xcb\xd5\ +\x16\xf4\xc7\xe9\xe08=\xc8>\x90\x1b\x98\xa7\xc8\xe8\x03\ +\x86\xfb \xb8\x8f\xa7\xa8y+\x00\xfe\xc1w\x04>\xa5\ +\xc2\xde\x93\x95\x83w>\xb0h\xdc\xb7D\x10-\x97g\ +\xae\xd0\xc7>R\xf0\xb3\xe2\x5cNA\x80\xdfa\xff\xaa\ +@Lv9\xe5W\x82\xbb\x1c\x10\x03\x82z\x98\xe0K\ +\x07?\x1c\xc4\xb8\xf7 \x0a\xd2\x0eL\xa2{6T\ +\xfa\x1e\xfc\xa9\x90G\xe3\xb8\xf0\xec\x0b\xe1\xbf1\x82P\ +\xe9\x9f\xaf+$C\x85Aa\xed\xa1?\x05Bi\x1c\ +\x17\xc3\xbf\x10\x0d,@\x90\xaf\x00s\xad\x06\xf9B>\ +\x8d\xdb\x12\xb8\x17\xc2?\xd8\x05~\x0a0\xdfj\x90/\ +\xf8\xb1\x04l>QC\x80\x06\x86#HQ\x809W\ +\x83| \x85\xc6\xa9X\xdc\x0b\xe1\x1f\xfc\xc2\xbb\x15`\ +\xde\xd5 \x1f\xd8\xcd*\xf2\xf5\x8b\xc5\xbf\x10\x0d\xe8!\ +\x08Q\x80\xb9W\x83l\x10B\xe3\xb2L\xdc\x8b\xa0\x81\ +\x81\x08\xbe)\xc0\x1a\xaaA:\x88E0\xa0<\xb8\x17\ +\xc2?\x83E\xe9\x8c\xe9\x0a\xb0\x96j(\x1f\x00\xce\xe6\ +\xd38,\x17\xfe\x85h@\x15\x81\x03\xab\xda&\xacJ\ +\x90O\xe3LU\x1a\xdc\x8b\xa0\x81:\x08vT\xd3@\ +\x95\x80|\x1aWud\xc1}5\x0dTI\x90+\xee\ +\xc5\xd0\x80\x03\xabZ\x1fPDH\xa7q#W\xdc\x8b\ +\xa0\x01\x90)\xa0W\xc4*\xc0\x9a\xab\x81\x82X\x1a'\ +2\xc9\xfbr\xd0\x00\xe8\x94`WT\xfb\x07*\x1fB\ +h\x5cH\xa5\xe7\xcb@\x03|\x1f\x11\xf8\x96\xaa}\xc5\ +\xbf\x1eR\xe8\xbd\xd7\x13\xc4\xc9\xaf\x18B4\x00~E\ +\xf0-C|\xa1Z7\xacx\xc8\xa7\xf7z8K\xc0\ +\xa7\xfb\xabp_\x0a\x1d@l\x09|E\x10c\x962\ +\x87\xa4\x1aJ\x81\x13\xd5\xa3zT\x8f\ +\xeaQ=D\x0ef\xf1\x8fe\xf2\xd3\xe0\xe2\x9fK\xf0\ +\xe7\x98\xe2\x9f\xd5\x84?\x0b\xcb\x83\xb2\xe4\x87\xb0\xbc\x11\ +\x96G\xc2\xf2\xaa\x84<+6A\xe5\x92\xf2PX^\ +\x0a\xcbSay+,\x8fK\xc8kay^\x5c\xde\ +\xb7E?L\x09j\xdf\x19\x84>\xf5{\xf4\x8b\x96\x9d\ +(\x90t\x88\xd0[\xfeB\xd0\x17\xc1r\x04G\x11\xdc\ +D\x10TIp\x93\x9e\xc3rzN\x7f\xc9K\xc7\x12\ +z\x0e\xf8\xe0\x0d\x11\xaccQ~y\xb0\xdd9\xac\xca\ +\xb7)\xf9\xc0\xa1\xe7\x14B\xcf\xd1\x90%\x107(\xef\ +>\x08\xad]\x1f\x81\x13\x828\x05X\xa7\xa4\x10G\xcf\ +Y\xbf\xbc{ \xf0\xf7J\x08& x\xa5\x00\xeb\x91\ +\x16^\xd1kP\x92d\x0f\x04\xd6^\x13\x81-\x824\ +\x05X\x83\xac\x90F\xaf\xa5fi{ \xb4\xf6-,\ +E\xe8\x9d)?`\xd3k\x12\xb9\x07\xac\xe24o\xfb\ +\x9b\xad]p\x0flY\x22\xce\x82\xc0\xfa\xe1\xac\xfc\x0e\ +4/\x0e\xd2\xe85\x16\xae\x9fU\x9c\xcfWe^'\ +)\xbcb\x09\xc9\x05\x16%+\x9d*\x7fn\xbf\xec\xfe\ +\xbc\x13\xab\xb8~\x00\xfa\xc2/\x94\xef\xbaE\xb58\xa0\ +\xee\x06\xd4\xd2Z\xd9\x92\xaa1\x08}\x9c\xa0\xd6,\xfc\ +]\xc5\xf5\xfc\x8c\xa3\xd7\xcc_\xff\xfa_\xb2n\xbav\ +\x14\xf4\xd6\x84\x9a\x0a\x19\xee\xd6dN\xe0!\x5c\xdb<\ +?*\x88d\x7fzL\xb2\xdf?\xc0\xfdgr\x1f\x9c\ +\xc5u\x0f\xd3\x0eM\xc7\xf5\x94q\xcf;\x5c\x0bIn\ +{\xb1\x8eU\xa4\xcfWl\xbe\x0f\xae\x97\xa5\x87k\xf8\ +f\xdd\xd8\x86\xd7I\xf5Z)\xbb\xe7\x04\xd4\x97\x80\xbe\ +O\xb9\x0f\xddp\x0d\x02\xa8\xf5&\xa7}\x08a\x15\xd9\ +2\x15\x14\xcf\xd4\xa5\xeb'\x9a\xe2Z\x87\xd03C\x96\ +\x01\xf56\xf2\xdf\x06\xe1\x9aET}a\x99\xee\xdd'\ +\xb3\x8a\xec8\xf9\xdb2\xb8\xdec\x1b\x5coI\x9e\xb5\ +\xc0\xf1>\xe4e\xe3\x9a\xb0P\xb3I\x86\xda\x03\x1cV\ +\x91\x0d+\xdf\xb5\xa39A\x9d\xcb\xdcG\xe7\xe5\xda\x03\ +Cx@\xbd2\x5c\x1bSz\xfe\xc8\xb7\xdf\xe5\x8aw\ +\xa8\x87\x0a\xfc\xecW\x0c\xa8\xef\x96q\xd6B\xda\xf9\xf2\ +}\x17r[{\xf2\xa6^\xb8N\xe4\xaf\x1c\xd0\x97\x19\ +j\x9bIA\x07Ar[?\xd4\xe1\x5c\xdb\x11\xf7\x87\ +\x96xp\x0aHNR,\xc9~w\x9f\xcc}|\x91\ +\xcc\x09>\x81\xe5\x1e\xd4\xe0+\xf8\x16I\xd5\x84\x95t\ +\x0f\xd2~\x90i.\xff\x96\x97\x1f\xc8o\xfdH\x87\xc9\ +\xf6\xdf\x8ff\x22\x81L\xcb\xcd\xc4\xb5\xc2q\xdf{D\ +/T\xefJ\xbd\x22\xfc!\xfd\x07\xeaiA_\x1e\xa8\ +/\x0c\xfd\x02%\x19\x05q\x11\xf8y\xe5\x90\x0b\xf2Y\ +?\xd4\xfc?4C\xa2\x1eB\xec\xcfad\xfa\xd1Y\ +t\x8fF\xedR\xeb\xba\xf2u?\xa8?\x0c\xb4\xc1\xcb\ +\xcb,\xf3\xf9\xb9\x0f\xce\x88\xaf\x15^\x11\xeb\x07\xba\xb7\ +m\x8f\xf8\xdd\xbd\xd2'\xc6\xe5\x90\xb9\xa1\xeeT\xff\xca\ +\xf2\xea/\xb0G\xd6\xfa\xb8>\x7fY:\x04\x9c\x19\xd0\ +\x19%\xac\x9b)\xfb\xfa\xa1\xcf\xe7\x99\xa5\xa5\xcb9\x1e\ +\x17\xf7m\xa6\xfa\xc6K+\xaf)]*\xfd\xc8,\x5c\ +\x1b\xb8\xb4\x01\xfc\x03j\xc2J\xb0\xc72\xae_\x17\xeb\ +8e\xf5\xba\xc9{\xe9C\xd7\x11\x95C\x9d$\xf4\x8c\ +\x0c\xb7\xe5X\x17\x14\xbb\xdd9\x19\xa2\xfb\xe4\xca{\xfd\ +\xe8\xf9\xd03\x13\xd7\xdd\x1538I1d\x8a\xd3 \ +\x89\xeb\xb8JD\x07\xe8|C\xff\xa1\xd2\x06\xeeMU\ +\xb6<\x94y\xfdY\xd7\xb7\x95:\x8fl\x9f\xed\xf2\xaf\ +\x17\x8cd\x5c\xca\xb6\x81\xb8&\x9f\xb8\x015\x19\xa9^\ +\x83\xa5\xee\x81l\xebG6\x08\xf4\xb7\x12\x8f\xfbXJ\ +G\xaf\xa0z\xc9\xb9\xf7O\x8b}7\xf0A\xa83_\ +\x06\xddI\xbf~\xdc?\xfd\x1fl\x9b\x8a\x1b\xd0C\x07\ +\xfb6*`\xed\xb0.\xb0\x87\xc1>\x16\xbd\x01<2\ +\xf3\xbc\x8d\x98^\xe9rX?\x9c\xfd\x1dC\xb1\xee)\ +nd^\xb2-\xeb\xfd\xd2\x03\xe8\xda\xcc\x1e\xa5\xda\x96\ +\xa0\x8f\x95\xa1\x0f\xca\xb4~\xa8\x09.n\xff\xa1\xb64\ +\xfc\xbb\xfc\xf8\x9e0P\xb2\xa74[\x03\xf7M\x11\xec\ +\xcb!\xd7\xf5kc=\x0etx\x91\xeb\xcfJ!S\ +\x9d\x87W\xe0\xfa\x9ba=\x19\xf4hq#\xef\xc5\xf5\ +\xb2\xce_\x85\xad\x9f\x9b\x99\x8c\xce\xc7\x90\x8a\xad\x8d\x88\ +t\xc2\xbc\x17\xe2{,C\xbf\x95B_jE\xac\xff\ +\xf0L\x5c'_$\xfe\xa1o\xc7\xde\xf1\x15\x8b\x7f\x90\ +?o\xee\x8a_\xffS/\xcaoZ!\xeboJ\xf5\ +\xb8\xcd\x11c\xa3\x22}\x1f\xec\xbb\x8a\xe3\x7f\xba\xd8F\ +\x04;Y\xdc\xc8\x09:^q\xf2\x1f\xfc<\x9bz\x97\ +j\x8fH\xa8\x83I\x07\xb0\xff\xce#K\xd5=\xb3\xae\ +0+N\xfe[Q}G\xf2\x9e_\xc32\x08\xf4\x80\ +b\x80~\x07\xf4\x87m\x9e\x8a\x88\xeb\x80\xee\xe9\xed(\ +v\xed\xd0\xeb\x00\xf7\xe7\xac\xb0\xf5S\x00>\x9fd\xfb\ +\xae\xb8\xdfw\x09\x80~\xbd\xc2\xfdA\xe5D\xfb\xa0\xdb\ +\x16D?\x13\xbb~\xd0=\x93\xcb\xf6\x85\xc8\xbc\xfeB\ +?\x85E\x13\x04\xda\xc5\xfb\x06T\x18\xed\xeb\xe0\x1e\x06\ +\xa5\xf5:\xc1\xb2\xafl?\x88\xe4\xeb\x17\xd7\x0b\x01\xf8\ +\xc0\xd6\xfe\xd8\x07\x0b1-\x0a\xe7\xcd\x8b\xc7\xf7\xe4\xb9\ +\x0fp\xee\xb7\x0fA\xe7+Z\xec\xdaa_\xa0\x7f\x87\ +L\xf6\xefr\x81\x9a\xc7\xd0\xcbl\xa31\xd5\x83P\xf8\ +,\xc39\xbc\x016 \x0f\xf3\xa2\x82\xf8\xb7\xd8\xde\xcf\ +\xbe\xe5L\xa6\x9f\xfc\x0f\xdbi\xb8o\xcc\x0a=\xd9\xf7\ +\x01\xbd\x0bb\x81\xf9Q\xc1\xe2\xd7N\x92\xb8\x973\xee\ +\xe1(\xad\xfd\x8b\xe8\x06\xde\x03\xfa+\xac\x0d\xe2\x91`\ +\xc7C?\xd0\x12{\x8a\xf4+\xe8\x0d&\xfa\x10\xb2q\ +\x0f\x9d\x82\x98\x97d.\xb2\x85Rw\x8d\x94\xde\x16D\ +\xef\x05yS\x9a\xbd\x89\x07\x8fKf]\xb6\x93T\xef\ +*\xbe\xfe\xe5T\xads\xe8A\xc5\xf9\xf9\x19\xd7\xbb/\ +~\xa6\x84\xf4)>\x1f\xfa\xfa\xba\xf49a\x9a\xe4 \ +}qv\xd1\xfeI\x14\xd7\xa6i\x10\xf1P\x88\xf3\x14\ +\xc4\xbc(\xf35\x10[\x95\xac\x17\x97(\xfc\xeb\xe2\x18\ +<\xf4\xdf\x12\x89\xce\x9f\x9f\xa8X4\xff\xd9\xd07\x16\ +l\xc0\xcc\xa4\xb2\x97\x9f\xfa\x9d\xea\x93gI\xf5\x81K\ +;0\x19=\xab;\x89\xed\x93\x12\xfd8\xb4\xa9\xbfC\ +sI\xdb7\x1e\xc7~%\xf1-\xc3\xf9\x93@\xe6\x95\ +N\xff\x88>\xb3\xfd\x0f\x88~~\xbe\x90M\x07}\xee\ +O/.\xd97Y\xc4\xc0=\x12\xd6\xb4\xa3\xe2\xa2X\ +v=\xa7\xe2\xda\xa1\xe7\xc9L\xcf\xf5d\xfa1s\xbc\ +'\xe0\xbb\x05^\x0a=\xa7\xa0\xf7\x94$\xeb\xa66\x98\ +C\xf9\x9aJ\xd7w\xcb^?\xf8\x15\x8e\xcfE\xc8\x16\ +\xad\xd7g]\xdfZ\xb4~\xd8+4OI\x06\xf8\xeb\ +\x8a\xceL\xc7\x92\xfd\xe6\x11\xaf\xa0\xfaI\xe4\x89\xec\x03\ +X\xfa\xe0\xe1\xe7S\xfe\xe5r\xf1X\x91\xf8\x87~s\ +\xdc\x94\xaf\x22\xdfD\xf1\x80\x16\xd4\xd9\x04\xfb\x03\xf1F\ +IF\xa6\xe7\xba\xc23\x8f\xf1\x1f\x17Q\xf6\x97$Z\ +:\x0f\xd3Pao\xb2\xf2\xf1U\x91\xfc\x1fb3\x90\ +g\x80\x07\xf4AK\xfe\x8a}\xdc\xd9\xb7\xf7`\x1a\xc5\ +:\x1d\xf8_\x90\x8e\x07\xfd<\xcb\x9cb^6\xf5=\ +9\xaf\x1f|/9\x81\x87e\xf1\xad\xc3\xdaK\xc6\xbf\ +\xd1\x1c3\xce-\xc7\xb178\x0b)\x8e\xbd\xe9x\x15\ +_\xa7\xd1\xa5}\xdf\xa3%\xeas\xcda\xc5\x90\xc9L\ +\xe3B]H\x1e\xeb\x87\x98`\xe6\xf9\x95\xb2\xf6\x99\xe6\ +\xe7\xcf\x8b\xf87=\x81~Zz\x98\xbe`\xde\x18`\ +\xbf\xd1\xdf\x80\xae\x07}\xb4\xa8\x9e\x8d\x8f\xd0\x99\x89\x17\ +\xe9\x0f\x83\xd8\x18\x15\xe3l&\xf3\xfa\x81\xc7C\x1c-\ +\xc5i \x8ds\x99t*\xfe\xdd\x01\xf1\xf9/\xb4\x9d\ +\x9b\xff\xee\x1e\x96\xf3\x05_#\xb1\xcf\x89\xeaw\xa4S\ +\xc8\x0b\x81\xf7\x00\xdf\x009\x9duu\x13\x99\x17\xe6\x89\ +\xf5\x1e\xf0\x8f\xe6\xdcq)\xc2\x11\x7f\xfd\xa5\xd8\xed%\ +\x06\xe2\xed`\xcf@l\x1cb\xc2\x98\xff\xc8\xeeS\xe7\ +\xe7\xbf\x94\x9e\xff\x04\xeb\xdf6\xa0\x98\x8c\xe7$~\xc6\ +g\xbfd\xbfW\xc1>\x8e\x14\xcd@\xec\x87\xa2\xfd\xa2\ +\xbf\x85\xb3\x94\x89t\xb4b=\xfa\xd09\xc2\xfc?7\ +\x13\xef\x19\xce\x0b@2\x13\xd6\x0c\xba<\xee\x01Z\x98\ +\x03'\xd3\xba\xf9\xc0\xcf\x7f*=\xff\x8d\xbf\xfe\x0cV\ +\xd1\xfaA\x0f*\xb1~Q\xdf\xd5\x15\xdf/\x12~\x07\ +v\x05\xf4\xa8\xdbj\x8ay\x09\xf0\xc8\xd4\xbd\xe3\xb1N\ +\x05{\x86\xf5\x05\xf8[\xbeM)\x9fu\xf3\x81\x9f\xff\ +Vz\xfe#\xce_3\xc1k\xc68\xca\xcd\xc0zh\ +\xf2\x06\x89\xec\x8b\xb2Ad\x8f6\x1dy\x9c\xed\xb2`\ +=K\xc2\xfcW\xe0]\x80\x93\xd4]\xa30\xe0x\xe6\ +J\x89s\x0c\x14\x11\x84\xf3_\xcb\xce\x7f\xb6\x14\xc0\x91\ +\xe2\xf6?\x95\x14\x84\xf3\x9f\xff\xd8\xfc\xf7?\xfd\xfeC\ +\xf5\xfd\x97\xea\xfbO\xd5\xf7\xdf\xc4\xde\x05\xfb\xa3\xee?\ +\x8a\xd8\x83?\xee\xfe\xab\x98=\xf8\xa3\xee?\x97\xb2\x0f\ +\xbf\xdd\xfdw\xba\xcc\x00I\xd7?\xe0\xd7\xd9\xe1\xd7\xd3\ +\xe1\xd7\xd1\xe1\xd7\xcb\xe1\xd7\xc5\xe1\xd7k\xa8\xae{S\ +\xc9\x83I\xfd(\xc4G0\xf5\x93_\x1f\x83_\x07\x83\ +_\xff\x82_\xe7\xc2\x84\x8fw\xa8\x13a\x84\xc0\x9c\x10\ +\xa8\x13\xd1\xaa\xec:\x11\x22\xce\x85\x06\x82A\x086!\ +\xb8\x8e\xe0\x19\x82\x08\x16\xc5\x83\xe5\x09\x11\xf4\xb3\xaf\xd3\ +\xef\x1aD\xbf[b\xba\x171os\x04\x81\x08R\x7f\ +\x01\xaf\x12\x86T\xfa\xdd\xe6\xc2\xeb\x90`\xee=\x10\xf8\ +\x22(\xa8\x84y\x0bC\x01=\x97\x1e\xe2\xd6 4\xf7\ +\xc9\x08b\x14`\xde\xc2\x10C\xcf\xad\xd8\x1aD\xcc\x9d\ +\xa5\x00s\x15\x07,\xe15\xb0\x8a\xd3\x8c\x22\xee\xbb(\ +<\x14\xa3%\x16u>|\x15`n\x92\x82/\xab\xf8\ +\x99\x863.\xdf\xb3Z\xccw\xa6#\xe4O\xd3&%\ +\x8b3\x8b\x85\x02z\xce\xfc\xbd\x0f\x94\xcf\xbc\xe9\xb8\xf6\ +\x0a}\x9cW\x011\xdb\xac+\x0ed\xce\x9dC\xd8\xdf\ +\x9bs\xff\x14\x99\xed\xbb\x1b\xdf\x8f\x06\x7f[a|G\ +:\xbfS \xabH6\xc9\xce\xdf\xd1\xbc!\xef\x16\xe6\ +\x9c\x1bv\x11\xc7vx\x05yb\x82\x15<\x92\x97\x93\ +F\xb2\xbf<%\xb3|\x9c\xb0\x1fU\x8a\xbc\xa0TV\ +\x91\x5c\x95m\xcf\xd1{S\xf7\x8c\xc1\xf1\x8b\xd2\xee\x8f\ +\x88\x1b\xe0\x93\x87|\x10|\xaf\xa0|y\xad|\x9d@\ +J\x1a\xa7b\xad\x10'\x87{~\xb2\x0d\x1e\xce\x9f\x01\ +\x7fn9\xe8\x89\xaf\xcfH5w\xf0\x1fC.\xbaX\ +:\x91b@\xdc5m\xffDI\xd7\xc0\xd7\xc5\xca?\ +\x7f\xeb\xe68\x97\xa9\xb4\x5c3\xbc\xab\xec\x5c\x9c\xe3\xc1\ +\xcf}\xc4\xf7\x02\xca\x88\xe3\xc3\xdf\xe2\x9c\xa0\xb2i\x89\ +\xafG\x96s\xefu\xf0\xbdX\x88?\x8b\x9f\xc3'\x1c\ +\xe7\x85\xbc\x0b\xb8\xab\x02yS\x90\xe3\x02\xb9\xdbp\xcf\ +\x0a\x9f\x95R\xee\xa1\xb2?=\xa2cA\xa5\xae\xe1U\ +\xb9\xe7O\xe7!\x88\x8b\xaf\xc3\x9ar\x82\x8e\x15\xdd\xf7\ +,\x96w(\xc0\xff\xd1\xb9I?2\x13\xf1\xa0'b\ +\xd7\x00\xeb/\xe3\x9e@\xf9\xe7\x8f\x00\xf8\xb9\xc8\xb9g\ +\xa7\x91\x99\x1e\xab\x0b\xf3\x08\xca|\x16\xce{\xeb\x8ep\ +\xe1#\xf2y\x90c\x06\xb9\x87\xa5\xc4\x06\xcb7\x7f\xfa\ +\x0e;'9\xae\xe4\xdc\x0b\xf2\xa9<8\xfc\xb7\xe5\xe0\ +\xe3\xb0\x06\xfb\x7fH\xf6\x87\x07\xa2q\x10|B~\xfb\ +\x8f\xde\x95yi\x9d\xc8\xf7@^(\x8e\xc5K\xa3\x13\ +\xc0\x9d\x97}\x13D\xe6{Q\xb9a\xdd\xc5\xe1\xb3|\ +\xf3\xb7n!\xf2^\x07\xc4\x1f\x0b\xf3H\xca;w>\ +\xac\xd0\xc3:F\x89\x81\xf0\x0a\xb9\x1eb\x9e-\xf9\xfc\ +!/\x1f\xf1\x10\xce\x8f\x92\xe7\x16\xee\xb9\x83\xee S\ +\x5c\x13\xdf\xb5\x9e^\x227\x11\x06\xe8L2\xcf\x1fr\ +\xfa\xb6\x0f\x11y\xaf+\xdbo\xbf\xec\xf1w|o\xae\ +\x1b\xce\xaf,A\x9bO/\x8b\xcb_+\xc7\xfc)\x1a\ +\x15\xa5\xdfd^(\xf3>\x9c\x04@\xe7H\x22\xbe/\ +< G\x0a\xe7\xe3\xc8:\xff\xfd\x93\xf0\xfd\xb1\xe2\xc4\ +\xcf\xa5j<\xc8\xe1>\x09\xce\xef\x12q_\x9d\xfd\xee\ +\x1e\x95\xe7$\xe3\xfc!\x87\x81\x97\x97Ur\xff/\xad\ +\x95\xcf\xfe\xafi\x87u\xea\x12\xfb\x1f\x19 \xfb\xfe\x8b\ +\xc8w\xe1\x8f\x9c{'e\xcfy\xc0\xf9D\xbdpN\ +\x9d\xf0\xa0\xee\xeb\x89\xfc^\xb9\xf8\x0f\xe4W\xe6G\xde\ +\xc1\xb6\x09\xbe\x9b\x02\x80\xfe\x1f\xf2\xb4\x81ve\xe3?\ +\xdad\xfa\xa9\x85\x22\xef\xfbg]\xdb\x22;\xff\x01\x80\ +\xdc\xa1\xf5\x9d\xa9;$p\xb7\x04\xc9M\x0c\x90s\x22\ +\xd3}\x12]L\xdf\x90\x9f/\xf8\x1e\xce\x19\x17:c\xf9\xaf\ +\xfdp\xce\x1b\xf0\xe5\xack\x9b\xb1\x1e\x09:2\xce\xb3\ +-_\x9e1}_x\x98H\xb9\x08#\xfb\xe6\x8e\xd2\ +t\xc1b\xf3\x07\x19\x0awKA\x87\x843S\x10\x1f\ +\x85u\xe1bg\x0c\xe9o\xdc\xb4\x84\xe28F\xf6\x17\ +\xd8(\xec\xcfO0\x0d\x17\xe1\xa2\x14|\xd0~\x07\xb8\ +\xeb\x07w\xeaE\x0d\x90e8?M\x92\xf9\xc3>\xec\ +\x1c^\xe2\xee~A\xec+:\x87W\x97\xbe\xdb=\xab\ +T{\x11\xdf\xed\xb6\xd0\xc6x\xc2:\x85\xa0\xbfG \ +O\x15\xceM\xd6\xd5\x8d\xe2k\x05p9d\xe6\xe5\x0d\ +\x92\xdb/X\xbf)\x99\xf7\x0by\x99p\x1f\x8f\xff~\ +\xe0\x05\xe2\x06\xe8q\x90\xef\x96\xb8L\x0b\xd9XVX\ +nfyo\xc2k\x06\xff\x04\xc8o\xb8;\x095\xd3\ +\x00\xb7\xa5\xd9\x91\x14O+3\xef\xbb8\xfd\x8b\xb9\xb3\ +\x02\xb5\xca\xf0\xbe\xc1\xbf?\xbd\x22\xf6\x9d\x9c\x84\xf7\xd4\ +\xfd\x1at\x9e!\x8f\xb1p]H\x87\x84\xfcE|>\ +%\xb9\x13\xf0>\xa4(/\xb8\xf4\xf3\xc3\x8f{\x14\x9e\ +%\xb0A\x0a\xdf\x8b\xecS\xc8\xa3\xc4\xfa\x0d\xdc/X\ +\xdbQ,\xad\xc2\x80\x9cu\x9c\xbf\x86\xd6\x0a\xb8\x97f\ +\xe4\xbf\xbd[\x16\xcd\x0b\x02?fC\xcf_\x07\xf3\x82\ +\xdcG\x1eh\x1d\x0e\xf8lQw\xab\x9a\xe19\xe1\xda\ +\x16\xe9?\xc5\xbe;\xdboo!\x8d\x97w\xfe\xa0\x97\ +@-\x1a\xea~\x94\xc4\xfe\x1f~\xbc\xa9\xe8w\xc0\xff\ +VPwW\xc0\xee\x815\xa4\xee\x1d\x87\xcf\x1b\xf8+\ +3\x5c\x17\x93\xd9\xc8\xae\xc69\xae\x90;)\xe0C\x00\ +\x1e\xce\xbf\xf3\x92\xe9eW\xcal\x05\xe6\xcd\xce\xc3\xf4\ +\x82m\x94\x95\xe5\xce\xff\xe5\xc7\xcaD\xf27\xb8\xc3\x01\ +\xf2\x0f\xe8\x16\xdf\x99\xb5\xd0.\xba\xbb\x079\xaahM\ +\xb0\xb6\xcc\x0b\xab\xf0\x9a\x0a\xf1\x0e\xf2\xe8\xf4b|\x07\ +\x18\xe7}\x0b\x9eSn\x01>\xe7@\x97\xc0\xa3\xa1f\ +a\x92\xad\xa1\xb4\xf6\x03?\xceW\xd2\x7f\x8b\xe6\x01\xbc\ +\x9f?\xc0?YB\xc7,\xbc\xcbW\xb2\xde\x14\xe8\x03\ +8o\xfb\xe0T\x5c_\x09x\x00\x9c#\xb8\xbb\x07\xbe\ +g|\x9f\x91\x9fw,\x9d\xee\xc7\xf7\xdf\x8a\xf6\x9f\xa3\ +\xf9\x00\x0f)\x88\x0dG\xf0\x12\xdf;(\xf7\x1e\x15\xf3\ +\xf7\x0b\x82\x5cj\xa7\xf2\xfd\xe7b\xe3\x17Pk\x09p\ +\x8bA\xb4\xfdPY \x18\xbf(=~T\x91\xf7u\ +\xa5\x07\xe1\xf8\x11?~W\x15zt\x8b\x8a\xdfU\xd9\ +\xf8iU\x8f_\xff\x0e\xf9\x03\xbfC\xfeFU\xcd\x9f\ +\xc1yD\x1a\x04\x11\x03?\xd5\x08\x22\x18~*\xd3\xf9\ +G\xd5Y`2\x0f&\xfc\x87Q\xb4\xaf1\xf0S\xad\ +h\xdf!OK\x9f\xa0z\xfa\x14\xe6ii\x8a\xce\xd3\ +\x12\xc2e\x0d\x16\x95\x1b\xb8\x07\xc1c\x16\xc5\x1f\xbeJ\ +\x091\xf43\xf6\xd0\xcf\xac!L3B\xefn\x8e\xe0\ +\x10\x82\xc4\x0a8w\x89\xf4\xb3\x9b\x8b8K\x00\xffC\ +\x10V\x01\xef\x15\x860\xfa]\xc2\xeb\xfe\x15\xef\x16\x9c\ +\x03\x7f\x1fj\xd0\xfbR\xceg\xe8\x8a\xd6!%\xb73\ +\x0e\xb1\x8ahMr|\xd3\xbayaM|d\x1b\x81\ +\x9f\x18|;\xe9\xc7\xe6P9\x13\xe0\xd3-\xbbfj\ +\x22\xab\x88\xce%{7\xc4\xe4\xd6\x1b\xe1\xbc\x02\x5c\x93\ +\x1ej\x09\x09\xda\xedP\xbf\x22-\x01\xc7\xa2\xc0\xee\xc2\ +\xbam\xe9\xfb\xc1?c\x12\xac[\x07\xfb9\xe0\xbd\x12\ +\xd5\xc1G\xf6\x19\xd8\xcbP\xf3\xae\x949\xf0\xcfw\x99\ +\xefN?6\xbb\x14\x9f\x10W\xec\x9c\xa0\xde\x5c)v\ +?\x9f\xb7\x94\xb2\xe7:\x18\xcf\x90K\x22\xbc>\xf0)\ +\x80\x9f\x11h\x00\xd7@\xf0\xdfO\xf91\x84\xfc?P\ +\x03\x04|\x1c\x22\xf4\xf5\xaf\xa5\xbf_\x17\xfb\x8a\xc0\xaf\ +)8\xc0\x7f\x07\xef\xa4\xfch\xc5\xed'\xb0\xff\xc07\ +Y\xbc\xce\x17\x8f\xcc\xba\xbe\xa5\xfc\xef\x07\xbf\xde\x89y\ +\xc5\xfcz\xb0\x0f\xa9\xb8N\x9a\xb6h\xfa\xa6\xf7\x19h\ +T\xf0n5\xcc9ycOa<\x94\xfe~\xf0k\ +\x85y\x0a\xe0\x99C\xc7d\xca\xb07\xe9\xfc\x1b\xa8g\ +U\xb4\x05<\xea\xfey\xf1\xef\x8a\x7f?\xf8\x0d\xd1^\ +\x82?\x80?\x0a\xbeGIZ\xa7\x86\x8a\x8b\xb9\xfc[\ +\xcc\xf7-\x22^\x22\xfe\xfdP3\xd5i`\xb1\xb8N\ +\xde\x93\xcbd\x19y\x0f\xc5\xe7\x0f~\xcf\x9f\x9f\x04\xce\ +\xc2\x03:\x9e+\xc9\xfb\x9bb\xba\x17\xac\x17\x00\xfeM\ +\xc9\xf9\xab.\xb6\xaf\xe1Ny\xe1\xfe\xc5\xbc\xc0|S\ +\x80nJ\x7f\xff\xf6!\xc5\xea\xa5\xe5>\xf6\x90\xf0\xdd\ +\xf4\xfa\x11\xaf\x14\xc4\x1f\xc4@\x85\xe2I\xa5\xe3\x1f\xed\ +\x1f\xf0\x0f\xa0y\xc8\xad\xc0\xb9\x08\x92\xc6\xa3p\xbd\xbd\ +1\xc5\xf6/\xef\xd9\x15\xe18\x84\x88\xf7\x0b\xd8\xf5\xe8\ +o\x81\x06!\xbf\x07\xe7\xf9@\xcc\x03\x7f_2\xbb_\ +\xd0\xcf\x04CD=\xa4\xa2\xf7\xf3{\xbd ~S\x18\ +[\xa1c\xeb\xe0\x7f\x84\xfc\x0c\x88\xf3\xe2{\xde6\xad\ +K\xc5;U\x93eN1\xdc\x81\x5c\x02?\xa9\xc8\xf3\ +\x0fy~;\x86\xe2\xde2 _\xf2^\x5c\xa3\xe8\xd4\ +B\x9b\xaa\x1b\xc6?\xc2\xe8,A\x1c2\xeb\x86\x13Y\ +8g\xe1\x18\x02:\xf7\xe0\x8b\x17\x96\x15\x98vK\xc6\ +\x80\xa8\xf7C]\x1c\xc4\xbf\x0b\xe7\x9a\xfe\x83\x92\xe3\xe8\ +\x99\xa2r/ 7\x12\xe2\x18\x10\xa7\x009\x0b\xf1\x11\ +\xf0\xbd\xc13\xa0\x86\xa5p\xfe\x16\xf8\xcaD\xf0>\x81\ +\xf5\xf3\xcf:\x95\xc3\x00\xfc\x16\xea\xeb\x80\xfc\xc6\xf2V\ +`\x80\xcf\x1e\xeaxB\x0c\x0c\xd7\x92E<\x11\xf2\x93\ +\xb0\xbfVD\xdc\x01\xf2\xc5\xc0\x17*&g\x8d\xd6\x91\ +\xa9\xda\x80\xb9\xf7]1\xae3\x5c\x17b\xff6\xe4\xba\ +B\x1cVp\x80\x9f\x1bbU\xc9\x1b\x8c\x8a\xf1\x16Q\ +\x03\xea2\xc1\xbe\x94\xc23\xf8\xfa9\xf5\xd9\xba\x05\xf6\ +E\x83\xdf\x16x5\xd0>\xaeOq}+>;\xd0\ +?\x04\xe2\xc4\x98F\x817\x8b\x88\xcd\x81\xdf\x19jU\ +\x80\x5c\x869\x96\x91\xab\xc7\xb7\x0d\x8ax.Z\x1b\xd4\ +\x82\x85\xb8\x1b\xce\x0f\x82\x18(\x9d\xfb\x0by\xa4\xb8\x9e\ +\x14\xf0`\xc8SC4\x9e\xed\xbb\x0b\xe7\xffB\xedJ\ +\x1cs<<\x93\xf2\xc1JVG\x8eo\x97$\x16\xf1\ +\xac\xce\xb8n\x0d\xc8p*\x8fX\xe0\x19\xc2>?\xc1\ +\xfb\xed\x82y\xd5\x92\xf9\x05\xf9\xfagI\xfd[\xfa\xdc\ +\xe5\xf2\x00_\xff\xe6\xdb\x1fO*\xf8}\x82 h\x7f\ +(\x82\xfdUi\xf6ge\xdb\xdf\xccJ\xf4\xc6\xc0\xbb\ +\xc1O\xa1IP\xbe\x8aB?E\x8d\x92~\x0az\xce\ +\x0d\x100\x11\xbcG\x90\x8e C\x0c\xa4\xd3\x7f\xc3\xa4\ +\xbf\xc3\xff\xee9\x04\xdc\x12\xb8\x11\x7fv\xb9\xf4w\xf8\ +\xef\xe5\x96\xf8\x1e\xe4C >\x0du\xe7 \xa6\x07\xf9\ +'B|\x82+0\xe7b\xdf\x858\x19\xd4\xbc\x05\xdd\ +\x06\xc7\x82\xe9\xdeeX\xbe\xad-\xc6{\xf8\xeb-\xe4\ +C\xa0\x8f\xf0\xfbH\x80L\x86\x5c\xd7\xfc\x08\xbf\xc2\xba\ +3\xa0\xeb\x0a\xd4\x92\xe5\xefU\xe1\xf7!\xf7\x0f\x06<\ +\x03\xea\xc9\xe0\xba\xd7\xd6\xcd\xb1\xbc\x80\xb8\x92\x90\xbe\x9e\ +Q\xf8\xfd\xc2zDo\xb0n\x8c\xf3\xe2-\x04\xe2g\ +\x88_S\xb9\x08\xf9T~\x1b\x15\xdf\x11\xf8>U\x1f\ +\x06x<\xe4d\x95\xc8o\xc49\x08]q\xfdH\x88\ +\x9b'Q9*E\xdf\x07\x1b\x0b\xed7\xd4\xc3\xc3}\ +;\x84\xeb\xe5\xf2\xeb\xb1!\x1d\x02rQh\x1eN}\ +\x1fz\x06B\xdcxe\x0b\xec+H?\xb5\x80\xea\xaf\ +\x22X\xbb\x13\xfd?U\x9f\x93\xc4u\x04i}\x1f\x7f\ +\x1f\xf0\x022\x15\xea{\x81M\x08\xf8\x02\x9d\x18\xea\x99\ +\xa6\xee\x1c\x86\xf5\xf5\xec\xdb{q\xcc\x98\x9b\x9e\x88\xf5\ +OZ\xfee\xa0\x9f\xe9`\x93\xc1\x9cqn\x08]\x03\ +\x12\xf2xA\xbe\xc2w\xf89p \xfb\xa0G\x8a\x00\ +\xbdP\xf4\x8c\xf0\x93q\xde\x1a\xe7\x99C>\x04\xe8f\ +\xd0O\x03\xe4 \xc4z\xa1\x87\x16\xc4[\xa9\xbb\x0a\xc5\ +\xe8\x98:\x0b\xcbu\xb9)\xdb\x07Sz\xa0`\xcc\x16\ +\xeau\x01\x9e\xf8=\xe2\x8a\xcb\x1e>\xfdR\xe7g\xb9\ +\x0e\xb7\x1c\xb2I\xf0\xfc\xc8t~e\x1d\xff\x07\x9d\xab\ +\xf3\x85\ \x00\x00_\x84\ I\ I*\x00\x08\x00\x00\x00\x17\x00\xfe\x00\x04\x00\x01\x00\x00\ @@ -26805,336 +26919,336 @@ qt_resource_struct = b"\ \x00\x00\x03\xa8\x00\x02\x00\x00\x00\x01\x00\x00\x00+\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x06\x0c\x00\x01\x00\x00\x00\x01\x00\x00\xde\xc4\ -\x00\x00\x01y\x1f\xa4\xb3Q\ -\x00\x00\x16\x86\x00\x00\x00\x00\x00\x01\x00\x05\x97+\ +\x00\x00\x01y\xd2\xb2\xf5B\ +\x00\x00\x16\x86\x00\x00\x00\x00\x00\x01\x00\x05\x9eC\ \x00\x00\x01x\xc7F\xed\xa9\ -\x00\x00\x16:\x00\x00\x00\x00\x00\x01\x00\x05\x95\x7f\ +\x00\x00\x16:\x00\x00\x00\x00\x00\x01\x00\x05\x9c\x97\ \x00\x00\x01x\xc7F\xf0\x97\ -\x00\x00\x16`\x00\x00\x00\x00\x00\x01\x00\x05\x96S\ +\x00\x00\x16`\x00\x00\x00\x00\x00\x01\x00\x05\x9dk\ \x00\x00\x01x\xc7F\xeb4\ -\x00\x00\x16\x1c\x00\x00\x00\x00\x00\x01\x00\x05\x94\x8c\ +\x00\x00\x16\x1c\x00\x00\x00\x00\x00\x01\x00\x05\x9b\xa4\ \x00\x00\x01x\xc7F\xf0\x87\ \x00\x00\x03\xa8\x00\x02\x00\x00\x00\x1f\x00\x00\x001\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x13\xb4\x00\x00\x00\x00\x00\x01\x00\x05\x80\xf9\ +\x00\x00\x13\xb4\x00\x00\x00\x00\x00\x01\x00\x05\x88\x11\ \x00\x00\x01x\xc7D\x85\xca\ -\x00\x00\x14\x06\x00\x00\x00\x00\x00\x01\x00\x05\x83\x8d\ +\x00\x00\x14\x06\x00\x00\x00\x00\x00\x01\x00\x05\x8a\xa5\ \x00\x00\x01x\xc7D\x85\xcc\ -\x00\x00\x15v\x00\x00\x00\x00\x00\x01\x00\x05\x90T\ +\x00\x00\x15v\x00\x00\x00\x00\x00\x01\x00\x05\x97l\ \x00\x00\x01x\xc7D\x85\xc3\ -\x00\x00\x12\xf0\x00\x00\x00\x00\x00\x01\x00\x05z\x87\ +\x00\x00\x12\xf0\x00\x00\x00\x00\x00\x01\x00\x05\x81\x9f\ \x00\x00\x01x\xc7D\x83\xc5\ -\x00\x00\x12|\x00\x00\x00\x00\x00\x01\x00\x05w\x97\ +\x00\x00\x12|\x00\x00\x00\x00\x00\x01\x00\x05~\xaf\ \x00\x00\x01x\xc7D\x85\xbb\ -\x00\x00\x152\x00\x00\x00\x00\x00\x01\x00\x05\x8d\xc0\ +\x00\x00\x152\x00\x00\x00\x00\x00\x01\x00\x05\x94\xd8\ \x00\x00\x01x\xc7D\x85e\ -\x00\x00\x12\x9e\x00\x00\x00\x00\x00\x01\x00\x05x\xe1\ +\x00\x00\x12\x9e\x00\x00\x00\x00\x00\x01\x00\x05\x7f\xf9\ \x00\x00\x01x\xc7D\x85\xd0\ -\x00\x00\x14\xf6\x00\x00\x00\x00\x00\x01\x00\x05\x8b,\ +\x00\x00\x14\xf6\x00\x00\x00\x00\x00\x01\x00\x05\x92D\ \x00\x00\x01x\xc7D\x84\xb4\ -\x00\x00\x11\xce\x00\x01\x00\x00\x00\x01\x00\x05s\x95\ +\x00\x00\x11\xce\x00\x01\x00\x00\x00\x01\x00\x05z\xad\ \x00\x00\x01x\xc7D\x83\xca\ -\x00\x00\x12(\x00\x00\x00\x00\x00\x01\x00\x05u\xe9\ +\x00\x00\x12(\x00\x00\x00\x00\x00\x01\x00\x05}\x01\ \x00\x00\x01x\xc7D\x85\xd2\ -\x00\x00\x12\x0c\x00\x01\x00\x00\x00\x01\x00\x05u>\ +\x00\x00\x12\x0c\x00\x01\x00\x00\x00\x01\x00\x05|V\ \x00\x00\x01x\xc7D\x84\x12\ -\x00\x00\x11\xf0\x00\x00\x00\x00\x00\x01\x00\x05s\xf4\ +\x00\x00\x11\xf0\x00\x00\x00\x00\x00\x01\x00\x05{\x0c\ \x00\x00\x01x\xc7D\x84\x12\ -\x00\x00\x12\xc8\x00\x01\x00\x00\x00\x01\x00\x05z+\ +\x00\x00\x12\xc8\x00\x01\x00\x00\x00\x01\x00\x05\x81C\ \x00\x00\x01x\xc7D\x83\xcf\ -\x00\x00\x13\x12\x00\x00\x00\x00\x00\x01\x00\x05{\xd1\ +\x00\x00\x13\x12\x00\x00\x00\x00\x00\x01\x00\x05\x82\xe9\ \x00\x00\x01x\xc7D\x85\xc7\ -\x00\x00\x13\xe0\x00\x00\x00\x00\x00\x01\x00\x05\x82C\ +\x00\x00\x13\xe0\x00\x00\x00\x00\x00\x01\x00\x05\x89[\ \x00\x00\x01x\xc7D\x85\xc8\ -\x00\x00\x13\x90\x00\x00\x00\x00\x00\x01\x00\x05\x7f\xaf\ +\x00\x00\x13\x90\x00\x00\x00\x00\x00\x01\x00\x05\x86\xc7\ \x00\x00\x01x\xc7D\x85d\ -\x00\x00\x13B\x00\x00\x00\x00\x00\x01\x00\x05}\x1b\ +\x00\x00\x13B\x00\x00\x00\x00\x00\x01\x00\x05\x843\ \x00\x00\x01x\xc7D\x85\xce\ -\x00\x00\x12\x5c\x00\x01\x00\x00\x00\x01\x00\x05w3\ +\x00\x00\x12\x5c\x00\x01\x00\x00\x00\x01\x00\x05~K\ \x00\x00\x01x\xc7D\x85-\ -\x00\x00\x15\xc4\x00\x01\x00\x00\x00\x01\x00\x05\x92\xe8\ +\x00\x00\x15\xc4\x00\x01\x00\x00\x00\x01\x00\x05\x9a\x00\ \x00\x00\x01x\xc7D\x83\xcb\ -\x00\x00\x14.\x00\x01\x00\x00\x00\x01\x00\x05\x84\xd7\ +\x00\x00\x14.\x00\x01\x00\x00\x00\x01\x00\x05\x8b\xef\ \x00\x00\x01x\xc7D\x85\xb9\ -\x00\x00\x14Z\x00\x01\x00\x00\x00\x01\x00\x05\x85\xa4\ +\x00\x00\x14Z\x00\x01\x00\x00\x00\x01\x00\x05\x8c\xbc\ \x00\x00\x01x\xc7D\x83\xcc\ -\x00\x00\x13h\x00\x00\x00\x00\x00\x01\x00\x05~e\ +\x00\x00\x13h\x00\x00\x00\x00\x00\x01\x00\x05\x85}\ \x00\x00\x01x\xc7D\x85d\ -\x00\x00\x14x\x00\x00\x00\x00\x00\x01\x00\x05\x86\x04\ +\x00\x00\x14x\x00\x00\x00\x00\x00\x01\x00\x05\x8d\x1c\ \x00\x00\x01x\xc7D\x85\xb6\ -\x00\x00\x15\x94\x00\x00\x00\x00\x00\x01\x00\x05\x91\x9e\ +\x00\x00\x15\x94\x00\x00\x00\x00\x00\x01\x00\x05\x98\xb6\ \x00\x00\x01x\xc7D\x85\xd4\ -\x00\x00\x14\x9c\x00\x00\x00\x00\x00\x01\x00\x05\x87N\ +\x00\x00\x14\x9c\x00\x00\x00\x00\x00\x01\x00\x05\x8ef\ \x00\x00\x01x\xc7D\x84\x0b\ -\x00\x00\x14\xba\x00\x00\x00\x00\x00\x01\x00\x05\x88\x98\ +\x00\x00\x14\xba\x00\x00\x00\x00\x00\x01\x00\x05\x8f\xb0\ \x00\x00\x01x\xc7D\x84\x0d\ -\x00\x00\x14\xd8\x00\x00\x00\x00\x00\x01\x00\x05\x89\xe2\ +\x00\x00\x14\xd8\x00\x00\x00\x00\x00\x01\x00\x05\x90\xfa\ \x00\x00\x01x\xc7D\x84\x0e\ -\x00\x00\x15\x14\x00\x00\x00\x00\x00\x01\x00\x05\x8cv\ +\x00\x00\x15\x14\x00\x00\x00\x00\x00\x01\x00\x05\x93\x8e\ \x00\x00\x01x\xc7D\x84\x0e\ -\x00\x00\x15X\x00\x00\x00\x00\x00\x01\x00\x05\x8f\x0a\ +\x00\x00\x15X\x00\x00\x00\x00\x00\x01\x00\x05\x96\x22\ \x00\x00\x01x\xc7D\x84\x0f\ -\x00\x00\x11\xba\x00\x01\x00\x00\x00\x01\x00\x05s6\ +\x00\x00\x11\xba\x00\x01\x00\x00\x00\x01\x00\x05zN\ \x00\x00\x01x\xc7D\x84\xb5\ -\x00\x00\x15\xf0\x00\x00\x00\x00\x00\x01\x00\x05\x93B\ +\x00\x00\x15\xf0\x00\x00\x00\x00\x00\x01\x00\x05\x9aZ\ \x00\x00\x01x\xc7D\x85\xc5\ \x00\x00\x03\xa8\x00\x02\x00\x00\x00\x08\x00\x00\x00Q\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00$\x98\x00\x00\x00\x00\x00\x01\x00\x06+\x0e\ +\x00\x00$\x98\x00\x00\x00\x00\x00\x01\x00\x062&\ \x00\x00\x01y+\x8f\x94\x0d\ -\x00\x00#\xa8\x00\x00\x00\x00\x00\x01\x00\x06\x16\xea\ +\x00\x00#\xa8\x00\x00\x00\x00\x00\x01\x00\x06\x1e\x02\ \x00\x00\x01y+\x8f\x94\x0b\ -\x00\x00$\x0a\x00\x00\x00\x00\x00\x01\x00\x06\x1e\xba\ +\x00\x00$\x0a\x00\x00\x00\x00\x00\x01\x00\x06%\xd2\ \x00\x00\x01y+\x8f\x94\x0b\ -\x00\x00$p\x00\x00\x00\x00\x00\x01\x00\x06&\x8c\ +\x00\x00$p\x00\x00\x00\x00\x00\x01\x00\x06-\xa4\ \x00\x00\x01x\xc7F\xf7d\ -\x00\x00#\xe6\x00\x00\x00\x00\x00\x01\x00\x06\x1a8\ +\x00\x00#\xe6\x00\x00\x00\x00\x00\x01\x00\x06!P\ \x00\x00\x01x\xc7F\xf6\xff\ -\x00\x00#D\x00\x00\x00\x00\x00\x01\x00\x06\x0f\x1e\ +\x00\x00#D\x00\x00\x00\x00\x00\x01\x00\x06\x166\ \x00\x00\x01x\xc7F\xf6\xed\ -\x00\x00$J\x00\x00\x00\x00\x00\x01\x00\x06\x22\x0a\ +\x00\x00$J\x00\x00\x00\x00\x00\x01\x00\x06)\x22\ \x00\x00\x01x\xc7F\xf6\xf0\ -\x00\x00#j\x00\x00\x00\x00\x00\x01\x00\x06\x13\xa0\ +\x00\x00#j\x00\x00\x00\x00\x00\x01\x00\x06\x1a\xb8\ \x00\x00\x01y+\x8f\x94\x0c\ \x00\x00\x16\xba\x00\x02\x00\x00\x009\x00\x00\x00Z\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00 :\x00\x00\x00\x00\x00\x01\x00\x05\xf1\xf4\ +\x00\x00 :\x00\x00\x00\x00\x00\x01\x00\x05\xf9\x0c\ \x00\x00\x01x\xc7F\xf0|\ -\x00\x00#\x0e\x00\x00\x00\x00\x00\x01\x00\x06\x0a1\ +\x00\x00#\x0e\x00\x00\x00\x00\x00\x01\x00\x06\x11I\ \x00\x00\x01x\xc7F\xed\xa1\ -\x00\x00\x1e\xb2\x00\x00\x00\x00\x00\x01\x00\x05\xe2\xb6\ +\x00\x00\x1e\xb2\x00\x00\x00\x00\x00\x01\x00\x05\xe9\xce\ \x00\x00\x01x\xc7F\xef\xf0\ -\x00\x00\x19\x08\x00\x00\x00\x00\x00\x01\x00\x05\xaf\x1d\ +\x00\x00\x19\x08\x00\x00\x00\x00\x00\x01\x00\x05\xb65\ \x00\x00\x01x\xc7F\xf0\xa1\ -\x00\x00!\xbc\x00\x00\x00\x00\x00\x01\x00\x05\xff\xfd\ +\x00\x00!\xbc\x00\x00\x00\x00\x00\x01\x00\x06\x07\x15\ \x00\x00\x01x\xc7F\xf0W\ -\x00\x00\x17@\x00\x00\x00\x00\x00\x01\x00\x05\x9d\xdd\ +\x00\x00\x17@\x00\x00\x00\x00\x00\x01\x00\x05\xa4\xf5\ \x00\x00\x01x\xc7F\xed\xd6\ -\x00\x00\x19\xae\x00\x00\x00\x00\x00\x01\x00\x05\xb2\xec\ +\x00\x00\x19\xae\x00\x00\x00\x00\x00\x01\x00\x05\xba\x04\ \x00\x00\x01x\xc7F\xe9{\ -\x00\x00\x22b\x00\x00\x00\x00\x00\x01\x00\x06\x04c\ +\x00\x00\x22b\x00\x00\x00\x00\x00\x01\x00\x06\x0b{\ \x00\x00\x01x\xc7F\xef\xab\ -\x00\x00\x1b\xde\x00\x00\x00\x00\x00\x01\x00\x05\xc5\xad\ +\x00\x00\x1b\xde\x00\x00\x00\x00\x00\x01\x00\x05\xcc\xc5\ \x00\x00\x01x\xc7F\xcb~\ -\x00\x00\x18,\x00\x00\x00\x00\x00\x01\x00\x05\xa5\x22\ +\x00\x00\x18,\x00\x00\x00\x00\x00\x01\x00\x05\xac:\ \x00\x00\x01x\xc7F\xf0\x90\ -\x00\x00\x1a\xd6\x00\x00\x00\x00\x00\x01\x00\x05\xba\xbf\ +\x00\x00\x1a\xd6\x00\x00\x00\x00\x00\x01\x00\x05\xc1\xd7\ \x00\x00\x01x\xc7F\xe9@\ -\x00\x00\x1e<\x00\x00\x00\x00\x00\x01\x00\x05\xdcu\ +\x00\x00\x1e<\x00\x00\x00\x00\x00\x01\x00\x05\xe3\x8d\ \x00\x00\x01x\xc7F\xf0=\ -\x00\x00 \xe0\x00\x00\x00\x00\x00\x01\x00\x05\xf6-\ +\x00\x00 \xe0\x00\x00\x00\x00\x00\x01\x00\x05\xfdE\ \x00\x00\x01x\xc7F\xf0\x03\ -\x00\x00\x1c\xba\x00\x00\x00\x00\x00\x01\x00\x05\xd0B\ +\x00\x00\x1c\xba\x00\x00\x00\x00\x00\x01\x00\x05\xd7Z\ \x00\x00\x01x\xc7F\xed\xd8\ -\x00\x00\x1f\x8e\x00\x00\x00\x00\x00\x01\x00\x05\xec\xea\ +\x00\x00\x1f\x8e\x00\x00\x00\x00\x00\x01\x00\x05\xf4\x02\ \x00\x00\x01x\xc7F\xed\xda\ -\x00\x00\x1cT\x00\x00\x00\x00\x00\x01\x00\x05\xcb\x82\ +\x00\x00\x1cT\x00\x00\x00\x00\x00\x01\x00\x05\xd2\x9a\ \x00\x00\x01x\xc7F\xcc\x09\ -\x00\x00\x18b\x00\x00\x00\x00\x00\x01\x00\x05\xa6\x14\ +\x00\x00\x18b\x00\x00\x00\x00\x00\x01\x00\x05\xad,\ \x00\x00\x01x\xc7F\xe9f\ -\x00\x00\x1e\xe8\x00\x00\x00\x00\x00\x01\x00\x05\xe4c\ +\x00\x00\x1e\xe8\x00\x00\x00\x00\x00\x01\x00\x05\xeb{\ \x00\x00\x01x\xc7F\xe9\x86\ -\x00\x00\x1b\x0c\x00\x00\x00\x00\x00\x01\x00\x05\xbc\x0d\ +\x00\x00\x1b\x0c\x00\x00\x00\x00\x00\x01\x00\x05\xc3%\ \x00\x00\x01x\xc7F\xcb\xfe\ -\x00\x00\x1d\x96\x00\x00\x00\x00\x00\x01\x00\x05\xd7\x13\ +\x00\x00\x1d\x96\x00\x00\x00\x00\x00\x01\x00\x05\xde+\ \x00\x00\x01x\xc7F\xe9\x82\ -\x00\x00!\x16\x00\x00\x00\x00\x00\x01\x00\x05\xf7\xeb\ +\x00\x00!\x16\x00\x00\x00\x00\x00\x01\x00\x05\xff\x03\ \x00\x00\x01x\xc7F\xe7N\ -\x00\x00\x17v\x00\x00\x00\x00\x00\x01\x00\x05\x9f\xff\ +\x00\x00\x17v\x00\x00\x00\x00\x00\x01\x00\x05\xa7\x17\ \x00\x00\x01x\xc7F\xe97\ -\x00\x00\x1f\xc4\x00\x00\x00\x00\x00\x01\x00\x05\xee\xfa\ +\x00\x00\x1f\xc4\x00\x00\x00\x00\x00\x01\x00\x05\xf6\x12\ \x00\x00\x01x\xc7F\xe7\xa5\ -\x00\x00\x22\x98\x00\x00\x00\x00\x00\x01\x00\x06\x06c\ +\x00\x00\x22\x98\x00\x00\x00\x00\x00\x01\x00\x06\x0d{\ \x00\x00\x01x\xc7F\xe6\xb8\ -\x00\x00\x19\xe4\x00\x00\x00\x00\x00\x01\x00\x05\xb4\x0b\ +\x00\x00\x19\xe4\x00\x00\x00\x00\x00\x01\x00\x05\xbb#\ \x00\x00\x01x\xc7F\xef\xeb\ -\x00\x00\x1d\x16\x00\x00\x00\x00\x00\x01\x00\x05\xd3\xe3\ +\x00\x00\x1d\x16\x00\x00\x00\x00\x00\x01\x00\x05\xda\xfb\ \x00\x00\x01x\xc7F\xef\xe2\ -\x00\x00\x1bn\x00\x00\x00\x00\x00\x01\x00\x05\xc1)\ +\x00\x00\x1bn\x00\x00\x00\x00\x00\x01\x00\x05\xc8A\ \x00\x00\x01x\xc7F\xef\x93\ -\x00\x00\x1af\x00\x00\x00\x00\x00\x01\x00\x05\xb7h\ +\x00\x00\x1af\x00\x00\x00\x00\x00\x01\x00\x05\xbe\x80\ \x00\x00\x01x\xc7F\xef\xee\ -\x00\x00\x19>\x00\x00\x00\x00\x00\x01\x00\x05\xaf\xef\ +\x00\x00\x19>\x00\x00\x00\x00\x00\x01\x00\x05\xb7\x07\ \x00\x00\x01x\xc7F\xf00\ -\x00\x00\x17\xec\x00\x00\x00\x00\x00\x01\x00\x05\xa2\xf2\ +\x00\x00\x17\xec\x00\x00\x00\x00\x00\x01\x00\x05\xaa\x0a\ \x00\x00\x01x\xc7F\xed\xd3\ -\x00\x00\x16\xd0\x00\x00\x00\x00\x00\x01\x00\x05\x9b\x19\ +\x00\x00\x16\xd0\x00\x00\x00\x00\x00\x01\x00\x05\xa21\ \x00\x00\x01x\xc7F\xef\xe6\ -\x00\x00!\xf2\x00\x00\x00\x00\x00\x01\x00\x06\x01P\ +\x00\x00!\xf2\x00\x00\x00\x00\x00\x01\x00\x06\x08h\ \x00\x00\x01x\xc7F\xf0f\ -\x00\x00 p\x00\x00\x00\x00\x00\x01\x00\x05\xf2\xfb\ +\x00\x00 p\x00\x00\x00\x00\x00\x01\x00\x05\xfa\x13\ \x00\x00\x01x\xc7F\xf0k\ -\x00\x00\x1f\x1e\x00\x00\x00\x00\x00\x01\x00\x05\xe5k\ +\x00\x00\x1f\x1e\x00\x00\x00\x00\x00\x01\x00\x05\xec\x83\ \x00\x00\x01x\xc7F\xed\xc2\ -\x00\x00\x1d\xcc\x00\x00\x00\x00\x00\x01\x00\x05\xd8!\ +\x00\x00\x1d\xcc\x00\x00\x00\x00\x00\x01\x00\x05\xdf9\ \x00\x00\x01x\xc7F\xf0\x0e\ -\x00\x00\x1a&\x00\x00\x00\x00\x00\x01\x00\x05\xb5\xde\ +\x00\x00\x1a&\x00\x00\x00\x00\x00\x01\x00\x05\xbc\xf6\ \x00\x00\x01x\xc7F\xf0%\ -\x00\x00\x18\x98\x00\x00\x00\x00\x00\x01\x00\x05\xa7M\ +\x00\x00\x18\x98\x00\x00\x00\x00\x00\x01\x00\x05\xaee\ \x00\x00\x01x\xc7F\xf0I\ -\x00\x00\x17\xac\x00\x00\x00\x00\x00\x01\x00\x05\xa1s\ +\x00\x00\x17\xac\x00\x00\x00\x00\x00\x01\x00\x05\xa8\x8b\ \x00\x00\x01x\xc7F\xf0,\ -\x00\x00\x22\xce\x00\x00\x00\x00\x00\x01\x00\x06\x08\x1f\ +\x00\x00\x22\xce\x00\x00\x00\x00\x00\x01\x00\x06\x0f7\ \x00\x00\x01x\xc7F\xed\xdd\ -\x00\x00!|\x00\x00\x00\x00\x00\x01\x00\x05\xfe\x91\ +\x00\x00!|\x00\x00\x00\x00\x00\x01\x00\x06\x05\xa9\ \x00\x00\x01x\xc7F\xf04\ -\x00\x00\x1f\xfa\x00\x00\x00\x00\x00\x01\x00\x05\xf0{\ +\x00\x00\x1f\xfa\x00\x00\x00\x00\x00\x01\x00\x05\xf7\x93\ \x00\x00\x01x\xc7F\xf0*\ -\x00\x00\x1er\x00\x00\x00\x00\x00\x01\x00\x05\xdd\xd6\ +\x00\x00\x1er\x00\x00\x00\x00\x00\x01\x00\x05\xe4\xee\ \x00\x00\x01x\xc7F\xed\xc6\ -\x00\x00\x1dV\x00\x00\x00\x00\x00\x01\x00\x05\xd5\xb7\ +\x00\x00\x1dV\x00\x00\x00\x00\x00\x01\x00\x05\xdc\xcf\ \x00\x00\x01x\xc7F\xf0@\ -\x00\x00\x1c\x14\x00\x00\x00\x00\x00\x01\x00\x05\xca)\ +\x00\x00\x1c\x14\x00\x00\x00\x00\x00\x01\x00\x05\xd1A\ \x00\x00\x01x\xc7F\xf0K\ -\x00\x00\x1bB\x00\x00\x00\x00\x00\x01\x00\x05\xbe&\ +\x00\x00\x1bB\x00\x00\x00\x00\x00\x01\x00\x05\xc5>\ \x00\x00\x01x\xc7F\xed\xcb\ -\x00\x00\x1e\x0c\x00\x00\x00\x00\x00\x01\x00\x05\xd9\xa3\ +\x00\x00\x1e\x0c\x00\x00\x00\x00\x00\x01\x00\x05\xe0\xbb\ \x00\x00\x01x\xc7F\xed\xc8\ -\x00\x00 \xb0\x00\x00\x00\x00\x00\x01\x00\x05\xf4(\ +\x00\x00 \xb0\x00\x00\x00\x00\x00\x01\x00\x05\xfb@\ \x00\x00\x01x\xc7F\xef\xa6\ -\x00\x00\x1c\x8a\x00\x00\x00\x00\x00\x01\x00\x05\xcd\x7f\ +\x00\x00\x1c\x8a\x00\x00\x00\x00\x00\x01\x00\x05\xd4\x97\ \x00\x00\x01x\xc7F\xed\xce\ -\x00\x00\x17\x10\x00\x00\x00\x00\x00\x01\x00\x05\x9c\xd8\ +\x00\x00\x17\x10\x00\x00\x00\x00\x00\x01\x00\x05\xa3\xf0\ \x00\x00\x01x\xc7F\xf0\x80\ -\x00\x00\x1f^\x00\x00\x00\x00\x00\x01\x00\x05\xeb\x8c\ +\x00\x00\x1f^\x00\x00\x00\x00\x00\x01\x00\x05\xf2\xa4\ \x00\x00\x01x\xc7F\xf0:\ -\x00\x00\x19~\x00\x00\x00\x00\x00\x01\x00\x05\xb1p\ +\x00\x00\x19~\x00\x00\x00\x00\x00\x01\x00\x05\xb8\x88\ \x00\x00\x01x\xc7F\xf0(\ -\x00\x00\x222\x00\x00\x00\x00\x00\x01\x00\x06\x02\x83\ +\x00\x00\x222\x00\x00\x00\x00\x00\x01\x00\x06\x09\x9b\ \x00\x00\x01x\xc7F\xef\xdd\ -\x00\x00\x1b\xae\x00\x00\x00\x00\x00\x01\x00\x05\xc3\x18\ +\x00\x00\x1b\xae\x00\x00\x00\x00\x00\x01\x00\x05\xca0\ \x00\x00\x01x\xc7F\xed\xd1\ -\x00\x00!L\x00\x00\x00\x00\x00\x01\x00\x05\xf9\xa7\ +\x00\x00!L\x00\x00\x00\x00\x00\x01\x00\x06\x00\xbf\ \x00\x00\x01y+\x8f\x93{\ -\x00\x00\x1a\xa6\x00\x00\x00\x00\x00\x01\x00\x05\xb92\ +\x00\x00\x1a\xa6\x00\x00\x00\x00\x00\x01\x00\x05\xc0J\ \x00\x00\x01x\xc7F\xf0\x0c\ -\x00\x00\x18\xd8\x00\x00\x00\x00\x00\x01\x00\x05\xa8\xa5\ +\x00\x00\x18\xd8\x00\x00\x00\x00\x00\x01\x00\x05\xaf\xbd\ \x00\x00\x01x\xc7F\xed\xa4\ -\x00\x00\x1c\xf0\x00\x00\x00\x00\x00\x01\x00\x05\xd2\x83\ +\x00\x00\x1c\xf0\x00\x00\x00\x00\x00\x01\x00\x05\xd9\x9b\ \x00\x00\x01x\xc7F\xe9<\ -\x00\x00\x0e\xba\x00\x00\x00\x00\x00\x01\x00\x04(&\ +\x00\x00\x0e\xba\x00\x00\x00\x00\x00\x01\x00\x04/>\ \x00\x00\x01y+\x8f\x94\x12\ -\x00\x00\x0d\x0a\x00\x00\x00\x00\x00\x01\x00\x03\x91\x87\ +\x00\x00\x0d\x0a\x00\x00\x00\x00\x00\x01\x00\x03\x98\x9f\ \x00\x00\x01y+\x8f\x93\xdc\ -\x00\x00\x0e\x80\x00\x00\x00\x00\x00\x01\x00\x04#\x0e\ +\x00\x00\x0e\x80\x00\x00\x00\x00\x00\x01\x00\x04*&\ \x00\x00\x01y+\x8f\x94\x08\ -\x00\x00\x0d~\x00\x00\x00\x00\x00\x01\x00\x03\xf4\x82\ +\x00\x00\x0d~\x00\x00\x00\x00\x00\x01\x00\x03\xfb\x9a\ \x00\x00\x01y+\x8f\x93\xcd\ -\x00\x00\x09\xf6\x00\x00\x00\x00\x00\x01\x00\x032\x17\ +\x00\x00\x09\xf6\x00\x00\x00\x00\x00\x01\x00\x039/\ \x00\x00\x01y+\x8f\x94\x10\ -\x00\x00\x09f\x00\x01\x00\x00\x00\x01\x00\x02i(\ +\x00\x00\x09f\x00\x01\x00\x00\x00\x01\x00\x02p@\ \x00\x00\x01x\xc7F\xf5\xfe\ -\x00\x00\x07\x12\x00\x00\x00\x00\x00\x01\x00\x01\x87\xf3\ +\x00\x00\x07\x12\x00\x00\x00\x00\x00\x01\x00\x01\x8f\x0b\ \x00\x00\x01y+\x8f\x93\xce\ -\x00\x00\x08:\x00\x00\x00\x00\x00\x01\x00\x01\xa3\x1b\ +\x00\x00\x08:\x00\x00\x00\x00\x00\x01\x00\x01\xaa3\ \x00\x00\x01y+\x8f\x94\x0a\ -\x00\x00\x0f$\x00\x00\x00\x00\x00\x01\x00\x04jD\ +\x00\x00\x0f$\x00\x00\x00\x00\x00\x01\x00\x04q\x5c\ \x00\x00\x01x\xc7F\xf6G\ -\x00\x00\x0e\x10\x00\x00\x00\x00\x00\x01\x00\x04\x15\xa7\ +\x00\x00\x0e\x10\x00\x00\x00\x00\x00\x01\x00\x04\x1c\xbf\ \x00\x00\x01y+\x8f\x93\xe3\ -\x00\x00\x08\xd2\x00\x00\x00\x00\x00\x01\x00\x02^f\ +\x00\x00\x08\xd2\x00\x00\x00\x00\x00\x01\x00\x02e~\ \x00\x00\x01y+\x8f\x93\xd6\ -\x00\x00\x0eL\x00\x00\x00\x00\x00\x01\x00\x04\x1d\xe2\ +\x00\x00\x0eL\x00\x00\x00\x00\x00\x01\x00\x04$\xfa\ \x00\x00\x01y+\x8f\x94\x09\ -\x00\x00\x09*\x00\x00\x00\x00\x00\x01\x00\x02f\x89\ +\x00\x00\x09*\x00\x00\x00\x00\x00\x01\x00\x02m\xa1\ \x00\x00\x01y+\x8f\x94\x07\ -\x00\x00\x0c \x00\x00\x00\x00\x00\x01\x00\x03u!\ +\x00\x00\x0c \x00\x00\x00\x00\x00\x01\x00\x03|9\ \x00\x00\x01y+\x8f\x93\xd5\ -\x00\x00\x07z\x00\x00\x00\x00\x00\x01\x00\x01\x96/\ +\x00\x00\x07z\x00\x00\x00\x00\x00\x01\x00\x01\x9dG\ \x00\x00\x01y+\x8f\x93\xdf\ -\x00\x00\x08x\x00\x00\x00\x00\x00\x01\x00\x01\xbe\xd0\ +\x00\x00\x08x\x00\x00\x00\x00\x00\x01\x00\x01\xc5\xe8\ \x00\x00\x01x\xc7F\xf6*\ -\x00\x00\x0f\x9c\x00\x00\x00\x00\x00\x01\x00\x04\x87Q\ +\x00\x00\x0f\x9c\x00\x00\x00\x00\x00\x01\x00\x04\x8ei\ \x00\x00\x01y+\x8f\x94\x12\ -\x00\x00\x08T\x00\x00\x00\x00\x00\x01\x00\x01\xa9(\ +\x00\x00\x08T\x00\x00\x00\x00\x00\x01\x00\x01\xb0@\ \x00\x00\x01x\xc7F\xf61\ -\x00\x00\x0cb\x00\x00\x00\x00\x00\x01\x00\x03\x81c\ +\x00\x00\x0cb\x00\x00\x00\x00\x00\x01\x00\x03\x88{\ \x00\x00\x01y+\x8f\x93\xda\ -\x00\x00\x07B\x00\x00\x00\x00\x00\x01\x00\x01\x8c\x97\ +\x00\x00\x07B\x00\x00\x00\x00\x00\x01\x00\x01\x93\xaf\ \x00\x00\x01y+\x8f\x94\x11\ -\x00\x00\x08\xf8\x00\x00\x00\x00\x00\x01\x00\x02b\x14\ +\x00\x00\x08\xf8\x00\x00\x00\x00\x00\x01\x00\x02i,\ \x00\x00\x01y+\x8f\x93\xce\ -\x00\x00\x0a\xc0\x00\x00\x00\x00\x00\x01\x00\x03N\xe6\ +\x00\x00\x0a\xc0\x00\x00\x00\x00\x00\x01\x00\x03U\xfe\ \x00\x00\x01y+\x8f\x93\xd8\ -\x00\x00\x09\xc8\x00\x01\x00\x00\x00\x01\x00\x03\x12$\ +\x00\x00\x09\xc8\x00\x01\x00\x00\x00\x01\x00\x03\x19<\ \x00\x00\x01x\xc7F\xf5\xf8\ -\x00\x00\x06\x92\x00\x00\x00\x00\x00\x01\x00\x01|\xed\ +\x00\x00\x06\x92\x00\x00\x00\x00\x00\x01\x00\x01\x84\x05\ \x00\x00\x01y+\x8f\x93\xcc\ -\x00\x00\x0a\xf8\x00\x00\x00\x00\x00\x01\x00\x03R\x98\ +\x00\x00\x0a\xf8\x00\x00\x00\x00\x00\x01\x00\x03Y\xb0\ \x00\x00\x01y+\x8f\x93\xdb\ -\x00\x00\x0d\x98\x00\x00\x00\x00\x00\x01\x00\x03\xf8 \ +\x00\x00\x0d\x98\x00\x00\x00\x00\x00\x01\x00\x03\xff8\ \x00\x00\x01y+\x8f\x93\xdc\ -\x00\x00\x0c<\x00\x00\x00\x00\x00\x01\x00\x03|B\ +\x00\x00\x0c<\x00\x00\x00\x00\x00\x01\x00\x03\x83Z\ \x00\x00\x01y+\x8f\x93\xde\ -\x00\x00\x0bZ\x00\x00\x00\x00\x00\x01\x00\x03W)\ +\x00\x00\x0bZ\x00\x00\x00\x00\x00\x01\x00\x03^A\ \x00\x00\x01y+\x8f\x93\xd8\ -\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x039\x16\ +\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x03@.\ \x00\x00\x01x\xc7F\xf60\ -\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x01\x00\x04`\xcc\ +\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x01\x00\x04g\xe4\ \x00\x00\x01y+\x8f\x94\x13\ -\x00\x00\x0fN\x00\x00\x00\x00\x00\x01\x00\x04\x7f\x0c\ +\x00\x00\x0fN\x00\x00\x00\x00\x00\x01\x00\x04\x86$\ \x00\x00\x01y+\x8f\x93\xe2\ -\x00\x00\x0dD\x00\x00\x00\x00\x00\x01\x00\x03\x95\x12\ +\x00\x00\x0dD\x00\x00\x00\x00\x00\x01\x00\x03\x9c*\ \x00\x00\x01x\xc7F\xf6\x18\ -\x00\x00\x0a0\x00\x00\x00\x00\x00\x01\x00\x034\xb6\ +\x00\x00\x0a0\x00\x00\x00\x00\x00\x01\x00\x03;\xce\ \x00\x00\x01y+\x8f\x93\xd9\ -\x00\x00\x060\x00\x00\x00\x00\x00\x01\x00\x01\x1a\xc3\ +\x00\x00\x060\x00\x00\x00\x00\x00\x01\x00\x01!\xdb\ \x00\x00\x01x\xc7F\xf6\x1b\ -\x00\x00\x0b\xe2\x00\x00\x00\x00\x00\x01\x00\x03p\xae\ +\x00\x00\x0b\xe2\x00\x00\x00\x00\x00\x01\x00\x03w\xc6\ \x00\x00\x01y+\x8f\x93\xd7\ -\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x84\xba\ +\x00\x00\x06\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x8b\xd2\ \x00\x00\x01y+\x8f\x93\xfd\ -\x00\x00\x07\xb8\x00\x00\x00\x00\x00\x01\x00\x01\x9bR\ +\x00\x00\x07\xb8\x00\x00\x00\x00\x00\x01\x00\x01\xa2j\ \x00\x00\x01y+\x8f\x94\x0f\ -\x00\x00\x0f\xce\x00\x00\x00\x00\x00\x01\x00\x04\x90\xf8\ +\x00\x00\x0f\xce\x00\x00\x00\x00\x00\x01\x00\x04\x98\x10\ \x00\x00\x01y+\x8f\x93\xcb\ -\x00\x00\x0e\xd0\x00\x01\x00\x00\x00\x01\x00\x04/\x99\ +\x00\x00\x0e\xd0\x00\x01\x00\x00\x00\x01\x00\x046\xb1\ \x00\x00\x01x\xc7F\xf5\xf3\ -\x00\x00\x06^\x00\x00\x00\x00\x00\x01\x00\x01zK\ +\x00\x00\x06^\x00\x00\x00\x00\x00\x01\x00\x01\x81c\ \x00\x00\x01y+\x8f\x94\x06\ -\x00\x00\x09\xb4\x00\x00\x00\x00\x00\x01\x00\x03\x0c\xa3\ +\x00\x00\x09\xb4\x00\x00\x00\x00\x00\x01\x00\x03\x13\xbb\ \x00\x00\x01y+\x8f\x93\xd0\ -\x00\x00\x0f\xf8\x00\x00\x00\x00\x00\x01\x00\x04\x93\xb2\ +\x00\x00\x0f\xf8\x00\x00\x00\x00\x00\x01\x00\x04\x9a\xca\ \x00\x00\x01x\xc7F\xf5\xf0\ -\x00\x00\x09\x86\x00\x00\x00\x00\x00\x01\x00\x02\x8c\x97\ +\x00\x00\x09\x86\x00\x00\x00\x00\x00\x01\x00\x02\x93\xaf\ \x00\x00\x01x\xc7F\xf6$\ -\x00\x00\x0d\xe4\x00\x01\x00\x00\x00\x01\x00\x03\xfb\xab\ +\x00\x00\x0d\xe4\x00\x01\x00\x00\x00\x01\x00\x04\x02\xc3\ \x00\x00\x01x\xc7F\xf6\x04\ -\x00\x00\x0c\xec\x00\x00\x00\x00\x00\x01\x00\x03\x8a\xa7\ +\x00\x00\x0c\xec\x00\x00\x00\x00\x00\x01\x00\x03\x91\xbf\ \x00\x00\x01y+\x8f\x94\x0e\ -\x00\x00\x0b\xaa\x00\x00\x00\x00\x00\x01\x00\x03[\xa0\ +\x00\x00\x0b\xaa\x00\x00\x00\x00\x00\x01\x00\x03b\xb8\ \x00\x00\x01x\xc7F\xf6L\ -\x00\x00\x06\xb8\x00\x00\x00\x00\x00\x01\x00\x01\x7f\x95\ +\x00\x00\x06\xb8\x00\x00\x00\x00\x00\x01\x00\x01\x86\xad\ \x00\x00\x01y+\x8f\x93\xe0\ -\x00\x00\x0c\xb0\x00\x00\x00\x00\x00\x01\x00\x03\x86\x07\ +\x00\x00\x0c\xb0\x00\x00\x00\x00\x00\x01\x00\x03\x8d\x1f\ \x00\x00\x01y+\x8f\x93\xdd\ -\x00\x00\x07\xea\x00\x00\x00\x00\x00\x01\x00\x01\x9d\xf4\ +\x00\x00\x07\xea\x00\x00\x00\x00\x00\x01\x00\x01\xa5\x0c\ \x00\x00\x01y+\x8f\x93\xe1\ -\x00\x00\x08\xb4\x00\x00\x00\x00\x00\x01\x00\x02H\xcc\ +\x00\x00\x08\xb4\x00\x00\x00\x00\x00\x01\x00\x02O\xe4\ \x00\x00\x01x\xc7F\xf6D\ -\x00\x00\x11\x06\x00\x00\x00\x00\x00\x01\x00\x05@\xf3\ +\x00\x00\x11\x06\x00\x00\x00\x00\x00\x01\x00\x05H\x0b\ \x00\x00\x01y+\x8f\x93\xd4\ -\x00\x00\x11\x88\x00\x00\x00\x00\x00\x01\x00\x05k\xae\ +\x00\x00\x11\x88\x00\x00\x00\x00\x00\x01\x00\x05r\xc6\ \x00\x00\x01y+\x8f\x93\xd1\ -\x00\x00\x11b\x00\x00\x00\x00\x00\x01\x00\x05Yl\ +\x00\x00\x11b\x00\x00\x00\x00\x00\x01\x00\x05`\x84\ \x00\x00\x01y+\x8f\x93\xcf\ -\x00\x00\x11\xa0\x00\x00\x00\x00\x00\x01\x00\x05o\xc9\ +\x00\x00\x11\xa0\x00\x00\x00\x00\x00\x01\x00\x05v\xe1\ \x00\x00\x01y+\x8f\x93\xd2\ -\x00\x00\x10\x94\x00\x00\x00\x00\x00\x01\x00\x059\xf7\ +\x00\x00\x10\x94\x00\x00\x00\x00\x00\x01\x00\x05A\x0f\ \x00\x00\x01x\xc7F\xf8/\ -\x00\x00\x106\x00\x00\x00\x00\x00\x01\x00\x05!\xc2\ +\x00\x00\x106\x00\x00\x00\x00\x00\x01\x00\x05(\xda\ \x00\x00\x01x\xc7F\xf8,\ -\x00\x00\x11 \x00\x00\x00\x00\x00\x01\x00\x05F\xfd\ +\x00\x00\x11 \x00\x00\x00\x00\x00\x01\x00\x05N\x15\ \x00\x00\x01x\xc7F\xf83\ -\x00\x00\x10\xdc\x00\x00\x00\x00\x00\x01\x00\x05@%\ +\x00\x00\x10\xdc\x00\x00\x00\x00\x00\x01\x00\x05G=\ \x00\x00\x01x\xc7F\xf8(\ -\x00\x00\x10`\x00\x00\x00\x00\x00\x01\x00\x05\x22O\ +\x00\x00\x10`\x00\x00\x00\x00\x00\x01\x00\x05)g\ \x00\x00\x01y+\x8f\x93\xd3\ -\x00\x00\x11J\x00\x00\x00\x00\x00\x01\x00\x05G\xa1\ +\x00\x00\x11J\x00\x00\x00\x00\x00\x01\x00\x05N\xb9\ \x00\x00\x01y+\x8f\x93\xca\ -\x00\x00\x10z\x00\x00\x00\x00\x00\x01\x00\x0509\ +\x00\x00\x10z\x00\x00\x00\x00\x00\x01\x00\x057Q\ \x00\x00\x01y+\x8f\x93\xc9\ -\x00\x00\x10\xbe\x00\x00\x00\x00\x00\x01\x00\x05:\xa6\ +\x00\x00\x10\xbe\x00\x00\x00\x00\x00\x01\x00\x05A\xbe\ \x00\x00\x01y+\x8f\x93\xe3\ " diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/aws_utils.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/aws_utils.py index b0c3c9c1b3..8152d2addc 100755 --- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/aws_utils.py +++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/aws_utils.py @@ -12,10 +12,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import boto3 from botocore.paginate import (PageIterator, Paginator) from botocore.client import BaseClient -from botocore.exceptions import ClientError +from botocore.exceptions import (ClientError, ConfigNotFound, NoCredentialsError, ProfileNotFound) from typing import Dict, List -from model import (constants, error_messages) +from model import error_messages from model.basic_resource_attributes import (BasicResourceAttributes, BasicResourceAttributesBuilder) """ @@ -65,8 +65,11 @@ def _initialize_boto3_aws_client(service: str, region: str = "") -> BaseClient: def setup_default_session(profile: str) -> None: - global default_session - default_session = boto3.session.Session(profile_name=profile) + try: + global default_session + default_session = boto3.session.Session(profile_name=profile) + except (ConfigNotFound, ProfileNotFound) as error: + raise RuntimeError(error) def get_default_account_id() -> str: @@ -76,6 +79,8 @@ def get_default_account_id() -> str: except ClientError as error: raise RuntimeError(error_messages.AWS_SERVICE_REQUEST_CLIENT_ERROR_MESSAGE.format( "get_caller_identity", error.response['Error']['Code'], error.response['Error']['Message'])) + except NoCredentialsError as error: + raise RuntimeError(error) def get_default_region() -> str: From 5d7aae9bd899e838e183a7b09a530e18261c4acb Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 3 Jun 2021 11:12:54 -0700 Subject: [PATCH 069/153] SPEC-2513 Fixes to enable w4459 (#1107) * fixing w4459 * Fixes for nounity * putting OLD_APARAM_USER in a common place to avoid duplicated declarations --- .../CryCommon/Maestro/Types/AnimParamType.h | 1 + Code/Framework/AzCore/Tests/AZStd/String.cpp | 16 ++++++------- .../AzCore/Tests/Math/Matrix4x4Tests.cpp | 10 ++++---- Code/Framework/AzCore/Tests/Math/ObbTests.cpp | 24 +++++++++---------- Code/Sandbox/Editor/QtViewPaneManager.cpp | 6 ++--- .../TrackView/SequenceBatchRenderDialog.cpp | 16 ++++++------- .../DiskLightFeatureProcessorInterface.h | 2 -- .../Atom/RHI/Vulkan/Code/Source/RHI/Queue.cpp | 10 ++++---- .../Source/RPI.Reflect/Shader/ShaderAsset.cpp | 5 +--- .../RPI.Reflect/Shader/ShaderVariantAsset.cpp | 5 +--- .../StaticLib/GraphCanvas/Styling/Parser.cpp | 6 ++--- .../Animation/Controls/UiTimelineCtrl.cpp | 4 ---- .../Code/Source/Animation/AnimNode.cpp | 1 - .../Code/Source/Cinematics/AnimNode.cpp | 1 - .../Code/Source/Cinematics/AnimPostFXNode.cpp | 1 - .../MicrophoneSystemComponent_Windows.cpp | 16 ++++++------- .../Source/Optimization/Constants.h | 4 ++-- .../Source/Optimization/LineSearch.cpp | 8 +++---- .../Tests/OptimizationTest.cpp | 10 ++++---- .../Benchmarks/PhysXBenchmarksUtilities.h | 6 ++--- .../Common/MSVC/Configurations_msvc.cmake | 1 - 21 files changed, 68 insertions(+), 85 deletions(-) diff --git a/Code/CryEngine/CryCommon/Maestro/Types/AnimParamType.h b/Code/CryEngine/CryCommon/Maestro/Types/AnimParamType.h index f7caf2db7f..4614b1638d 100644 --- a/Code/CryEngine/CryCommon/Maestro/Types/AnimParamType.h +++ b/Code/CryEngine/CryCommon/Maestro/Types/AnimParamType.h @@ -137,5 +137,6 @@ enum class AnimParamType Invalid = static_cast(0xFFFFFFFF) }; +static const int OLD_APARAM_USER = 100; #endif // CRYINCLUDE_CRYCOMMON_MAESTRO_TYPES_ANIMPARAMTYPE_H diff --git a/Code/Framework/AzCore/Tests/AZStd/String.cpp b/Code/Framework/AzCore/Tests/AZStd/String.cpp index 5b8c176f02..a48725309a 100644 --- a/Code/Framework/AzCore/Tests/AZStd/String.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/String.cpp @@ -1914,7 +1914,7 @@ namespace UnitTest TEST_F(String, StringView_CompareIsConstexpr) { using TypeParam = char; - auto MakeCompileTimeString1 = []() constexpr -> const TypeParam* + auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam* { return "HelloWorld"; }; @@ -1922,7 +1922,7 @@ namespace UnitTest { return "HelloPearl"; }; - constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1(); + constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1(); constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2(); constexpr basic_string_view lhsView(compileTimeString1); constexpr basic_string_view rhsView(compileTimeString2); @@ -1937,11 +1937,11 @@ namespace UnitTest TEST_F(String, StringView_CompareOperatorsAreConstexpr) { using TypeParam = char; - auto MakeCompileTimeString1 = []() constexpr -> const TypeParam* + auto TestMakeCompileTimeString1 = []() constexpr -> const TypeParam* { return "HelloWorld"; }; - constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1(); + constexpr const TypeParam* compileTimeString1 = TestMakeCompileTimeString1(); constexpr basic_string_view compareView(compileTimeString1); static_assert(compareView == "HelloWorld", "string_view operator== comparison has failed"); static_assert(compareView != "MadWorld", "string_view operator!= comparison has failed"); @@ -1955,7 +1955,7 @@ namespace UnitTest { auto swap_test_func = []() constexpr -> basic_string_view { - constexpr auto MakeCompileTimeString1 = []() constexpr -> const TypeParam* + constexpr auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam* { if constexpr (AZStd::is_same_v) { @@ -1977,7 +1977,7 @@ namespace UnitTest return L"InuWorld"; } }; - constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1(); + constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1(); constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2(); basic_string_view lhsView(compileTimeString1); basic_string_view rhsView(compileTimeString2); @@ -2001,7 +2001,7 @@ namespace UnitTest TYPED_TEST(BasicStringViewConstexprFixture, HashString_FunctionIsConstexpr) { - auto MakeCompileTimeString1 = []() constexpr -> const TypeParam* + auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam* { if constexpr (AZStd::is_same_v) { @@ -2012,7 +2012,7 @@ namespace UnitTest return L"HelloWorld"; } }; - constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1(); + constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1(); constexpr basic_string_view hashView(compileTimeString1); constexpr size_t compileHash = AZStd::hash>{}(hashView); static_assert(compileHash != 0, "Hash of \"HelloWorld\" should not be 0"); diff --git a/Code/Framework/AzCore/Tests/Math/Matrix4x4Tests.cpp b/Code/Framework/AzCore/Tests/Math/Matrix4x4Tests.cpp index a9baa3ddea..8c4fac86c2 100644 --- a/Code/Framework/AzCore/Tests/Math/Matrix4x4Tests.cpp +++ b/Code/Framework/AzCore/Tests/Math/Matrix4x4Tests.cpp @@ -59,7 +59,7 @@ namespace UnitTest TEST(MATH_Matrix4x4, TestCreateFrom) { - float testFloats[] = + float thisTestFloats[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, @@ -67,20 +67,20 @@ namespace UnitTest 13.0f, 14.0f, 15.0f, 16.0f }; float testFloatMtx[16]; - Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(testFloats); + Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(thisTestFloats); AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 2.0f, 3.0f, 4.0f)); AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(5.0f, 6.0f, 7.0f, 8.0f)); AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(9.0f, 10.0f, 11.0f, 12.0f)); AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(13.0f, 14.0f, 15.0f, 16.0f)); m1.StoreToRowMajorFloat16(testFloatMtx); - AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0); - m1 = Matrix4x4::CreateFromColumnMajorFloat16(testFloats); + AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0); + m1 = Matrix4x4::CreateFromColumnMajorFloat16(thisTestFloats); AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 5.0f, 9.0f, 13.0f)); AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(2.0f, 6.0f, 10.0f, 14.0f)); AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(3.0f, 7.0f, 11.0f, 15.0f)); AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(4.0f, 8.0f, 12.0f, 16.0f)); m1.StoreToColumnMajorFloat16(testFloatMtx); - AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0); + AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0); } TEST(MATH_Matrix4x4, TestCreateFromMatrix3x4) diff --git a/Code/Framework/AzCore/Tests/Math/ObbTests.cpp b/Code/Framework/AzCore/Tests/Math/ObbTests.cpp index de267b4265..5eb9057761 100644 --- a/Code/Framework/AzCore/Tests/Math/ObbTests.cpp +++ b/Code/Framework/AzCore/Tests/Math/ObbTests.cpp @@ -119,10 +119,10 @@ namespace UnitTest TEST(MATH_Obb, Contains) { - const Vector3 position(1.0f, 2.0f, 3.0f); - const Quaternion rotation = Quaternion::CreateRotationZ(DegToRad(30.0f)); - const Vector3 halfLengths(2.0f, 1.0f, 2.5f); - const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths); + const Vector3 testPosition(1.0f, 2.0f, 3.0f); + const Quaternion testRotation = Quaternion::CreateRotationZ(DegToRad(30.0f)); + const Vector3 testHalfLengths(2.0f, 1.0f, 2.5f); + const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths); // test some pairs of points which should be just either side of the Obb boundary EXPECT_TRUE(obb.Contains(Vector3(1.35f, 3.35f, 3.5f))); EXPECT_FALSE(obb.Contains(Vector3(1.35f, 3.4f, 3.5f))); @@ -134,10 +134,10 @@ namespace UnitTest TEST(MATH_Obb, GetDistance) { - const Vector3 position(5.0f, 3.0f, 2.0f); - const Quaternion rotation = Quaternion::CreateRotationX(DegToRad(60.0f)); - const Vector3 halfLengths(0.5f, 2.0f, 1.5f); - const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths); + const Vector3 testPosition(5.0f, 3.0f, 2.0f); + const Quaternion testRotation = Quaternion::CreateRotationX(DegToRad(60.0f)); + const Vector3 testHalfLengths(0.5f, 2.0f, 1.5f); + const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths); EXPECT_NEAR(obb.GetDistance(Vector3(5.3f, 3.2f, 1.8f)), 0.0f, 1e-3f); EXPECT_NEAR(obb.GetDistance(Vector3(5.1f, 1.1f, 3.7f)), 0.9955f, 1e-3f); EXPECT_NEAR(obb.GetDistance(Vector3(4.7f, 4.5f, 4.2f)), 0.6553f, 1e-3f); @@ -146,10 +146,10 @@ namespace UnitTest TEST(MATH_Obb, GetDistanceSq) { - const Vector3 position(1.0f, 4.0f, 3.0f); - const Quaternion rotation = Quaternion::CreateRotationY(DegToRad(45.0f)); - const Vector3 halfLengths(1.5f, 3.0f, 1.0f); - const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths); + const Vector3 testPosition(1.0f, 4.0f, 3.0f); + const Quaternion testRotation = Quaternion::CreateRotationY(DegToRad(45.0f)); + const Vector3 testHalfLengths(1.5f, 3.0f, 1.0f); + const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths); EXPECT_NEAR(obb.GetDistanceSq(Vector3(1.1f, 4.3f, 2.7f)), 0.0f, 1e-3f); EXPECT_NEAR(obb.GetDistanceSq(Vector3(-0.7f, 3.5f, 2.0f)), 0.8266f, 1e-3f); EXPECT_NEAR(obb.GetDistanceSq(Vector3(2.4f, 0.5f, 1.5f)), 0.5532f, 1e-3f); diff --git a/Code/Sandbox/Editor/QtViewPaneManager.cpp b/Code/Sandbox/Editor/QtViewPaneManager.cpp index b242f3d914..3949f0516e 100644 --- a/Code/Sandbox/Editor/QtViewPaneManager.cpp +++ b/Code/Sandbox/Editor/QtViewPaneManager.cpp @@ -121,7 +121,7 @@ protected: }; #endif -Q_GLOBAL_STATIC(QtViewPaneManager, s_instance) +Q_GLOBAL_STATIC(QtViewPaneManager, s_viewPaneManagerInstance) QWidget* QtViewPane::CreateWidget() @@ -611,12 +611,12 @@ void QtViewPaneManager::UnregisterPane(const QString& name) QtViewPaneManager* QtViewPaneManager::instance() { - return s_instance(); + return s_viewPaneManagerInstance(); } bool QtViewPaneManager::exists() { - return s_instance.exists(); + return s_viewPaneManagerInstance.exists(); } void QtViewPaneManager::SetMainWindow(AzQtComponents::DockMainWindow* mainWindow, QSettings* settings, const QByteArray& lastMainWindowState) diff --git a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp index 69322c481c..0abe3ced75 100644 --- a/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Sandbox/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -59,7 +59,7 @@ namespace { int fps; const char* fpsDesc; - } fps[] = { + } fpsOptions[] = { {24, "Film(24)"}, {25, "PAL(25)"}, {30, "NTSC(30)"}, {48, "Show(48)"}, {50, "PAL Field(50)"}, {60, "NTSC Field(60)"} }; @@ -213,9 +213,9 @@ void CSequenceBatchRenderDialog::OnInitDialog() m_ui->m_resolutionCombo->setCurrentIndex(0); // Fill the FPS combo box. - for (int i = 0; i < AZStd::size(fps); ++i) + for (int i = 0; i < AZStd::size(fpsOptions); ++i) { - m_ui->m_fpsCombo->addItem(fps[i].fpsDesc); + m_ui->m_fpsCombo->addItem(fpsOptions[i].fpsDesc); } m_ui->m_fpsCombo->setCurrentIndex(0); @@ -306,9 +306,9 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange() m_ui->m_destinationEdit->setText(item.folder); // fps bool bFound = false; - for (int i = 0; i < arraysize(fps); ++i) + for (int i = 0; i < arraysize(fpsOptions); ++i) { - if (item.fps == fps[i].fps) + if (item.fps == fpsOptions[i].fps) { m_ui->m_fpsCombo->setCurrentIndex(i); bFound = true; @@ -621,7 +621,7 @@ void CSequenceBatchRenderDialog::OnFPSEditChange() void CSequenceBatchRenderDialog::OnFPSChange(int itemIndex) { - m_customFPS = fps[itemIndex].fps; + m_customFPS = fpsOptions[itemIndex].fps; CheckForEnableUpdateButton(); } @@ -1543,13 +1543,13 @@ bool CSequenceBatchRenderDialog::SetUpNewRenderItem(SRenderItem& item) item.frameRange = Range(m_ui->m_startFrame->value() / m_fpsForTimeToFrameConversion, m_ui->m_endFrame->value() / m_fpsForTimeToFrameConversion); // fps - if (m_ui->m_fpsCombo->currentIndex() == -1 || m_ui->m_fpsCombo->currentText() != fps[m_ui->m_fpsCombo->currentIndex()].fpsDesc) + if (m_ui->m_fpsCombo->currentIndex() == -1 || m_ui->m_fpsCombo->currentText() != fpsOptions[m_ui->m_fpsCombo->currentIndex()].fpsDesc) { item.fps = m_customFPS; } else { - item.fps = fps[m_ui->m_fpsCombo->currentIndex()].fps; + item.fps = fpsOptions[m_ui->m_fpsCombo->currentIndex()].fps; } // prefix item.prefix = m_ui->BATCH_RENDER_FILE_PREFIX->text(); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index 50c0aa2455..ce911fecf7 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -46,8 +46,6 @@ namespace AZ uint16_t m_padding; // Explicit padding. }; - static constexpr size_t size = sizeof(DiskLightData); - //! DiskLightFeatureProcessorInterface provides an interface to acquire, release, and update a disk light. This is necessary for code outside of //! the Atom features gem to communicate with the DiskLightFeatureProcessor. class DiskLightFeatureProcessorInterface diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Queue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Queue.cpp index 5bebc92125..88d103d282 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Queue.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Queue.cpp @@ -45,7 +45,7 @@ namespace AZ Fence* fenceToSignal) { AZStd::vector vkCommandBuffers; - AZStd::vector vkWaitSemaphores; + AZStd::vector vkWaitSemaphoreVector; // vulkan.h has a #define called vkWaitSemaphores, so we name this differently AZStd::vector vkWaitPipelineStages; AZStd::vector vkSignalSemaphores; VkSubmitInfo submitInfo; @@ -65,11 +65,11 @@ namespace AZ return item->GetNativeSemaphore(); }); vkWaitPipelineStages.reserve(waitSemaphoresInfo.size()); - vkWaitSemaphores.reserve(waitSemaphoresInfo.size()); + vkWaitSemaphoreVector.reserve(waitSemaphoresInfo.size()); AZStd::for_each(waitSemaphoresInfo.begin(), waitSemaphoresInfo.end(), [&](auto& item) { vkWaitPipelineStages.push_back(item.first); - vkWaitSemaphores.push_back(item.second->GetNativeSemaphore()); + vkWaitSemaphoreVector.push_back(item.second->GetNativeSemaphore()); // Wait until the wait semaphores has been submitted for signaling. item.second->WaitEvent(); }); @@ -77,8 +77,8 @@ namespace AZ submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = nullptr; - submitInfo.waitSemaphoreCount = static_cast(vkWaitSemaphores.size()); - submitInfo.pWaitSemaphores = vkWaitSemaphores.empty() ? nullptr : vkWaitSemaphores.data(); + submitInfo.waitSemaphoreCount = static_cast(vkWaitSemaphoreVector.size()); + submitInfo.pWaitSemaphores = vkWaitSemaphoreVector.empty() ? nullptr : vkWaitSemaphoreVector.data(); submitInfo.pWaitDstStageMask = vkWaitPipelineStages.empty() ? nullptr : vkWaitPipelineStages.data(); submitInfo.commandBufferCount = static_cast(vkCommandBuffers.size()); submitInfo.pCommandBuffers = vkCommandBuffers.empty() ? nullptr : vkCommandBuffers.data(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp index 0a59772d6c..cf655d43f7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp @@ -10,6 +10,7 @@ * */ #include +#include #include #include @@ -34,10 +35,6 @@ namespace AZ uint32_t ShaderAsset::MakeAssetProductSubId(uint32_t rhiApiUniqueIndex, uint32_t subProductType) { - static constexpr uint32_t RhiIndexBitPosition = 30; - static constexpr uint32_t RhiIndexNumBits = 32 - RhiIndexBitPosition; - static constexpr uint32_t RhiIndexMaxValue = (1 << RhiIndexNumBits) - 1; - static constexpr uint32_t SubProductTypeBitPosition = 0; static constexpr uint32_t SubProductTypeNumBits = RhiIndexBitPosition - SubProductTypeBitPosition; static constexpr uint32_t SubProductTypeMaxValue = (1 << SubProductTypeNumBits) - 1; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp index 7864768351..5bcdcbb569 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp @@ -10,6 +10,7 @@ * */ #include +#include #include #include @@ -24,10 +25,6 @@ namespace AZ uint32_t ShaderVariantAsset::MakeAssetProductSubId( uint32_t rhiApiUniqueIndex, ShaderVariantStableId variantStableId, uint32_t subProductType) { - static constexpr uint32_t RhiIndexBitPosition = 30; - static constexpr uint32_t RhiIndexNumBits = 32 - RhiIndexBitPosition; - static constexpr uint32_t RhiIndexMaxValue = (1 << RhiIndexNumBits) - 1; - static constexpr uint32_t SubProductTypeBitPosition = 17; static constexpr uint32_t SubProductTypeNumBits = RhiIndexBitPosition - SubProductTypeBitPosition; static constexpr uint32_t SubProductTypeMaxValue = (1 << SubProductTypeNumBits) - 1; diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp index 319996949b..db07c3ca8e 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp @@ -1072,8 +1072,7 @@ namespace GraphCanvas if (!id.empty()) { - Selector selector = Selector::Get(id); - result.emplace_back(selector); + result.emplace_back(Selector::Get(id)); continue; } @@ -1111,8 +1110,7 @@ namespace GraphCanvas { bits.emplace_back(stateSelector); } - Selector selector = aznew CompoundSelector(std::move(bits)); - nestedSelectors.emplace_back(selector); + nestedSelectors.emplace_back(aznew CompoundSelector(std::move(bits))); } } diff --git a/Gems/LyShine/Code/Editor/Animation/Controls/UiTimelineCtrl.cpp b/Gems/LyShine/Code/Editor/Animation/Controls/UiTimelineCtrl.cpp index 9f7fae6041..0b18539c54 100644 --- a/Gems/LyShine/Code/Editor/Animation/Controls/UiTimelineCtrl.cpp +++ b/Gems/LyShine/Code/Editor/Animation/Controls/UiTimelineCtrl.cpp @@ -23,10 +23,6 @@ #include #include -static const QColor timeMarkerCol = QColor(255, 0, 255); -static const QColor textCol = QColor(0, 0, 0); -static const QColor ltgrayCol = QColor(110, 110, 110); - QColor InterpolateColor(const QColor& c1, const QColor& c2, float fraction) { const int r = (c2.red() - c1.red()) * fraction + c1.red(); diff --git a/Gems/LyShine/Code/Source/Animation/AnimNode.cpp b/Gems/LyShine/Code/Source/Animation/AnimNode.cpp index 421e9a4fe3..369f080a15 100644 --- a/Gems/LyShine/Code/Source/Animation/AnimNode.cpp +++ b/Gems/LyShine/Code/Source/Animation/AnimNode.cpp @@ -48,7 +48,6 @@ static const EUiAnimCurveType DEFAULT_TRACK_TYPE = eUiAnimCurveType_BezierFloat; // Old serialization values that are no longer // defined in IUiAnimationSystem.h, but needed for conversion: -static const int OLD_APARAM_USER = 100; static const int OLD_ACURVE_GOTO = 21; static const int OLD_APARAM_PARTICLE_COUNT_SCALE = 95; static const int OLD_APARAM_PARTICLE_PULSE_PERIOD = 96; diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimNode.cpp index 7fea8097ed..8398ad47fd 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimNode.cpp @@ -60,7 +60,6 @@ static const EAnimCurveType DEFAULT_TRACK_TYPE = eAnimCurveType_BezierFloat; // Old serialization values that are no longer // defined in IMovieSystem.h, but needed for conversion: -static const int OLD_APARAM_USER = 100; static const int OLD_ACURVE_GOTO = 21; static const int OLD_APARAM_PARTICLE_COUNT_SCALE = 95; static const int OLD_APARAM_PARTICLE_PULSE_PERIOD = 96; diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp index 67b6ab5cdb..992527d2c4 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimPostFXNode.cpp @@ -281,7 +281,6 @@ void CAnimPostFXNode::SerializeAnims(XmlNodeRef& xmlNode, bool bLoading, bool bL paramType.Serialize(trackNode, true); // Don't use APARAM_USER because it could change in newer versions // CAnimNode::SerializeAnims will then take care of that - static const unsigned int OLD_APARAM_USER = 100; paramType = static_cast(static_cast(paramType.GetType()) + OLD_APARAM_USER); paramType.Serialize(trackNode, false); } diff --git a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp index 8b3e3c2ce6..2eb840b253 100644 --- a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp +++ b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp @@ -51,11 +51,11 @@ namespace Audio // To avoid errors, we initialize COM here with the same model. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); - const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); + const CLSID CLSID_MMDeviceEnumerator_UUID = __uuidof(MMDeviceEnumerator); + const IID IID_IMMDeviceEnumerator_UUID = __uuidof(IMMDeviceEnumerator); HRESULT hresult = CoCreateInstance( - CLSID_MMDeviceEnumerator, nullptr, - CLSCTX_ALL, IID_IMMDeviceEnumerator, + CLSID_MMDeviceEnumerator_UUID, nullptr, + CLSCTX_ALL, IID_IMMDeviceEnumerator_UUID, reinterpret_cast(&m_enumerator) ); @@ -133,8 +133,8 @@ namespace Audio AZ_Assert(m_device != nullptr, "Attempting to start a Microphone session while the device is uninitialized - Windows!\n"); // Get the IAudioClient from the device - const IID IID_IAudioClient = __uuidof(IAudioClient); - HRESULT hresult = m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, reinterpret_cast(&m_audioClient)); + const IID IID_IAudioClient_UUID = __uuidof(IAudioClient); + HRESULT hresult = m_device->Activate(IID_IAudioClient_UUID, CLSCTX_ALL, nullptr, reinterpret_cast(&m_audioClient)); if (FAILED(hresult)) { @@ -182,8 +182,8 @@ namespace Audio } // Get the IAudioCaptureClient - const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); - hresult = m_audioClient->GetService(IID_IAudioCaptureClient, reinterpret_cast(&m_audioCaptureClient)); + const IID IID_IAudioCaptureClient_UUID = __uuidof(IAudioCaptureClient); + hresult = m_audioClient->GetService(IID_IAudioCaptureClient_UUID, reinterpret_cast(&m_audioCaptureClient)); if (FAILED(hresult)) { diff --git a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/Constants.h b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/Constants.h index d480fb9cd0..feb626aa50 100644 --- a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/Constants.h +++ b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/Constants.h @@ -27,6 +27,6 @@ namespace NumericalMethods::Optimization const double epsilon = 1e-7; // values recommended in Nocedal and Wright for constants in the Wolfe conditions for satisfactory solution improvement - const double c1 = 1e-4; - const double c2 = 0.9; + const double WolfeConditionsC1 = 1e-4; + const double WolfeConditionsC2 = 0.9; } // namespace NumericalMethods::Optimization diff --git a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp index 1325638dd2..06152446d6 100644 --- a/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp +++ b/Gems/PhysX/Code/NumericalMethods/Source/Optimization/LineSearch.cpp @@ -162,16 +162,16 @@ namespace NumericalMethods::Optimization { // if the value of f corresponding to alpha1 isn't sufficiently small compared to f at x0, // then the interval [alpha0 ... alpha1] must bracket a suitable point. - if ((f_alpha1 > f_x0 + c1 * alpha1 * df_x0) || (iteration > 0 && f_alpha1 > f_alpha0)) + if ((f_alpha1 > f_x0 + WolfeConditionsC1 * alpha1 * df_x0) || (iteration > 0 && f_alpha1 > f_alpha0)) { return SelectStepSizeFromInterval(alpha0, alpha1, f_alpha0, f_alpha1, df_alpha0, - f, x0, searchDirection, f_x0, df_x0, c1, c2); + f, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2); } // otherwise, if the derivative corresponding to alpha1 is large enough, alpha1 already // satisfies the Wolfe conditions and so return alpha1. double df_alpha1 = DirectionalDerivative(f, x0 + alpha1 * searchDirection, searchDirection); - if (fabs(df_alpha1) <= -c2 * df_x0) + if (fabs(df_alpha1) <= -WolfeConditionsC2 * df_x0) { LineSearchResult result; result.m_outcome = LineSearchOutcome::Success; @@ -184,7 +184,7 @@ namespace NumericalMethods::Optimization if (df_alpha1 >= 0.0) { return SelectStepSizeFromInterval(alpha1, alpha0, f_alpha1, f_alpha0, df_alpha1, - f, x0, searchDirection, f_x0, df_x0, c1, c2); + f, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2); } // haven't found an interval which is guaranteed to bracket a suitable point, diff --git a/Gems/PhysX/Code/NumericalMethods/Tests/OptimizationTest.cpp b/Gems/PhysX/Code/NumericalMethods/Tests/OptimizationTest.cpp index b02f13d8a4..92d7e0dcba 100644 --- a/Gems/PhysX/Code/NumericalMethods/Tests/OptimizationTest.cpp +++ b/Gems/PhysX/Code/NumericalMethods/Tests/OptimizationTest.cpp @@ -158,12 +158,12 @@ namespace NumericalMethods::Optimization double f_x0 = f_alpha0; double df_x0 = df_alpha0; LineSearchResult lineSearchResult = SelectStepSizeFromInterval(alpha0, alpha1, f_alpha0, f_alpha1, df_alpha0, - testFunctionRosenbrock, x0, searchDirection, f_x0, df_x0, c1, c2); + testFunctionRosenbrock, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2); EXPECT_TRUE(lineSearchResult.m_outcome == LineSearchOutcome::Success); // check that the Wolfe conditions are satisfied by the returned step size - EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + c1 * df_x0 * lineSearchResult.m_stepSize); - EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -c2 * df_x0); + EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + WolfeConditionsC1 * df_x0 * lineSearchResult.m_stepSize); + EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -WolfeConditionsC2 * df_x0); } TEST(OptimizationTest, LineSearch_VariousSearchDirections_SatisfiesWolfeCondition) @@ -180,8 +180,8 @@ namespace NumericalMethods::Optimization EXPECT_TRUE(lineSearchResult.m_outcome == LineSearchOutcome::Success); // check that the Wolfe conditions are satisfied by the returned step size - EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + c1 * df_x0 * lineSearchResult.m_stepSize); - EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -c2 * df_x0); + EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + WolfeConditionsC1 * df_x0 * lineSearchResult.m_stepSize); + EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -WolfeConditionsC2 * df_x0); } } diff --git a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksUtilities.h b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksUtilities.h index ab9bd58148..0971226644 100644 --- a/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksUtilities.h +++ b/Gems/PhysX/Code/Tests/Benchmarks/PhysXBenchmarksUtilities.h @@ -112,9 +112,9 @@ namespace PhysX::Benchmarks for (double percentile : percentiles) { //ensure the percentile is between 0.0 and 1.0 - const double epsilon = 0.001; - AZ::ClampIfCloseMag(percentile, 0.0, epsilon); - AZ::ClampIfCloseMag(percentile, 1.0, epsilon); + const double testEpsilon = 0.001; + AZ::ClampIfCloseMag(percentile, 0.0, testEpsilon); + AZ::ClampIfCloseMag(percentile, 1.0, testEpsilon); size_t idx = aznumeric_cast(std::round(percentile * (values.size() - 1))); std::nth_element(values.begin(), values.begin() + idx, values.end()); diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 24dffe56a6..f53b8aa769 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -74,7 +74,6 @@ ly_append_configurations_options( /wd4436 # the result of unary operator may be unaligned /wd4450 # declaration hides global declaration /wd4457 # declaration hides function parameter - /wd4459 # declaration hides global declaration # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From 6681a5376844f9e3fcb0faebe6ffe6983c9bfa03 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Thu, 3 Jun 2021 14:13:44 -0400 Subject: [PATCH 070/153] Add the ability to remove tags. Updated some descriptions, and updated some log messages to include parameters. --- scripts/o3de/o3de/project_properties.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index d8453a2c4f..7a9610a775 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -13,12 +13,13 @@ logging.basicConfig() def get_project_props(name: str = None, path: pathlib.Path = None) -> dict: proj_json = manifest.get_project_json_data(project_name=name, project_path=path) if not proj_json: - logger.error('Could not retrieve project.json file') + param = name if name else path + logger.error(f'Could not retrieve project.json file for {param}') return None return proj_json def edit_project_props(proj_path, proj_name, new_origin, new_display, - new_summary, new_icon, new_tag) -> int: + new_summary, new_icon, new_tag, remove_tag) -> int: proj_json = get_project_props(proj_name, proj_path) if not proj_json: @@ -36,6 +37,14 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display, if 'user_tags' not in proj_json: proj_json['user_tags'] = [] proj_json['user_tags'].append(new_tag) + if remove_tag: + if 'user_tags' in proj_json: + if remove_tag in proj_json['user_tags']: + proj_json['user_tags'].remove(remove_tag) + else: + logger.warn(f'{remove_tag} not found in user_tags for removal.') + else: + logger.warn(f'user_tags property not found for removal of tag {remove_tag}.') manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json') return 0 @@ -47,7 +56,8 @@ def _edit_project_props(args: argparse) -> int: args.project_display, args.project_summary, args.project_icon, - args.project_tag) + args.project_tag, + args.remove_tag) def add_parser_args(parser): group = parser.add_mutually_exclusive_group(required=True) @@ -65,7 +75,9 @@ def add_parser_args(parser): group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') group.add_argument('-pt', '--project-tag', type=str, required=False, - help='Adds a tag to canonical user tags. These tags are intended for documentation and filtering.') + help='Adds a tag to user tags. These tags are intended for documentation and filtering.') + group.add_argument('-rt', '--remove-tag', type=str, required=False, + help='Removes a tag from user tags. These tags are intended for documentation and filtering.') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: From 7bba5ed2fc6f91a66fd2fbaada65ac130d7b1c87 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Thu, 3 Jun 2021 14:43:13 -0400 Subject: [PATCH 071/153] Incorporated suggestion to use setdefault to handle missing tag property rather than explicitly checking for and creating it. --- scripts/o3de/o3de/project_properties.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 7a9610a775..63ff05a8da 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -34,9 +34,7 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display, if new_icon: proj_json['icon_path'] = new_icon if new_tag: - if 'user_tags' not in proj_json: - proj_json['user_tags'] = [] - proj_json['user_tags'].append(new_tag) + proj_json.setdefault('user_tags', []).append(new_tag) if remove_tag: if 'user_tags' in proj_json: if remove_tag in proj_json['user_tags']: @@ -75,9 +73,9 @@ def add_parser_args(parser): group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') group.add_argument('-pt', '--project-tag', type=str, required=False, - help='Adds a tag to user tags. These tags are intended for documentation and filtering.') + help='Adds a tag to user_tags property. These tags are intended for documentation and filtering.') group.add_argument('-rt', '--remove-tag', type=str, required=False, - help='Removes a tag from user tags. These tags are intended for documentation and filtering.') + help='Removes a tag from the user_tags property.') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: From e99a95d909948d51b02b6fefb3f393eace5b7aca Mon Sep 17 00:00:00 2001 From: mgwynn Date: Thu, 3 Jun 2021 15:02:18 -0400 Subject: [PATCH 072/153] Added copyright header for validation --- scripts/o3de/o3de/project_properties.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 63ff05a8da..69bd1b9406 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -1,3 +1,14 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + import argparse import json import os From dce87534c7d9a7cb1f686d3368998093cc08b2fa Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 14:37:16 -0500 Subject: [PATCH 073/153] Removing the Pyside implementation of the project manager python scripts (#1112) * Removing the Pyside implementation of the project manager python scripts * Removing reference to the scripts/project_manager directory The Install_common.cmake script reference to the project_manager directory has been removed. --- cmake/Platform/Common/Install_common.cmake | 1 - scripts/CMakeLists.txt | 1 - scripts/project_manager/CMakeLists.txt | 22 - scripts/project_manager/__init__.py | 10 - scripts/project_manager/projects.py | 804 ------------------ scripts/project_manager/pyside.py | 61 -- scripts/project_manager/tests/__init__.py | 10 - .../project_manager/tests/test_projects.py | 255 ------ scripts/project_manager/tests/test_pyside.py | 54 -- .../ui/create_from_template.ui | 94 -- scripts/project_manager/ui/create_gem.ui | 94 -- scripts/project_manager/ui/create_project.ui | 94 -- .../project_manager/ui/manage_gem_targets.ui | 165 ---- .../project_manager/ui/project_manager.ico | 3 - scripts/project_manager/ui/project_manager.ui | 407 --------- 15 files changed, 2075 deletions(-) delete mode 100644 scripts/project_manager/CMakeLists.txt delete mode 100755 scripts/project_manager/__init__.py delete mode 100755 scripts/project_manager/projects.py delete mode 100755 scripts/project_manager/pyside.py delete mode 100755 scripts/project_manager/tests/__init__.py delete mode 100755 scripts/project_manager/tests/test_projects.py delete mode 100755 scripts/project_manager/tests/test_pyside.py delete mode 100644 scripts/project_manager/ui/create_from_template.ui delete mode 100644 scripts/project_manager/ui/create_gem.ui delete mode 100644 scripts/project_manager/ui/create_project.ui delete mode 100644 scripts/project_manager/ui/manage_gem_targets.ui delete mode 100644 scripts/project_manager/ui/project_manager.ico delete mode 100644 scripts/project_manager/ui/project_manager.ui diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 710a8b266f..11260ab018 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -443,7 +443,6 @@ function(ly_setup_others) install(DIRECTORY ${LY_ROOT_FOLDER}/scripts/bundler - ${LY_ROOT_FOLDER}/scripts/project_manager ${LY_ROOT_FOLDER}/scripts/o3de DESTINATION ./scripts COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index d3c9640665..6df0f4b77f 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -12,5 +12,4 @@ add_subdirectory(detect_file_changes) add_subdirectory(commit_validation) add_subdirectory(o3de) -add_subdirectory(project_manager) add_subdirectory(ctest) diff --git a/scripts/project_manager/CMakeLists.txt b/scripts/project_manager/CMakeLists.txt deleted file mode 100644 index 36c9ad0360..0000000000 --- a/scripts/project_manager/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -ly_download_associated_package(pyside2) - -ly_add_pytest( - NAME test_pyside - PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_pyside.py -) - -ly_add_pytest( - NAME test_projects - PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_projects.py -) \ No newline at end of file diff --git a/scripts/project_manager/__init__.py b/scripts/project_manager/__init__.py deleted file mode 100755 index 4d5680a30d..0000000000 --- a/scripts/project_manager/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py deleted file mode 100755 index f9f40aa4bf..0000000000 --- a/scripts/project_manager/projects.py +++ /dev/null @@ -1,804 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# PySide project and gem selector GUI - -import os -import pathlib -import sys -import argparse -import json -import logging -import subprocess -from logging.handlers import RotatingFileHandler -from typing import List -from pyside import add_pyside_environment, is_pyside_ready, uninstall_env - -engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) -sys.path.append(engine_path) -executable_path = '' - -logger = logging.getLogger() -logger.setLevel(logging.INFO) - -from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register - -o3de_folder = manifest.get_o3de_folder() -o3de_logs_folder = manifest.get_o3de_logs_folder() -project_manager_log_file_path = o3de_logs_folder / "project_manager.log" -log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1) -formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') -log_file_handler.setFormatter(formatter) -logger.addHandler(log_file_handler) - -logger.info("Starting Project Manager") - - -def initialize_pyside_from_parser(): - # Parse arguments up top. We need to know the path to our binaries and QT libs in particular to load up - # PySide - parser = argparse.ArgumentParser() - parser.add_argument('--executable-path', required=True, help='Path to Executable to launch with project') - parser.add_argument('--binaries-path', default=None, help='Path to QT Binaries necessary for PySide. If not' - ' provided executable_path folder is assumed') - parser.add_argument('--parent-pid', default=0, help='Process ID of launching process') - - args = parser.parse_args() - - logger.info(f"parent_pid is {args.parent_pid}") - global executable_path - executable_path = args.executable_path - binaries_path = args.binaries_path or os.path.dirname(executable_path) - - # Initialize PySide before imports below. This adds both PySide python modules to the python system interpreter - # path and adds the necessary paths to binaries for the DLLs to be found and load their dependencies - add_pyside_environment(binaries_path) - - -if not is_pyside_ready(): - initialize_pyside_from_parser() - -try: - from PySide2.QtWidgets import QApplication, QDialogButtonBox, QPushButton, QComboBox, QMessageBox, QFileDialog - from PySide2.QtWidgets import QListView, QLabel - from PySide2.QtUiTools import QUiLoader - from PySide2.QtCore import QFile, QObject, Qt, Signal, Slot - from PySide2.QtGui import QIcon, QStandardItemModel, QStandardItem -except ImportError as e: - logger.error(f"Failed to import PySide2 with error {e}") - exit(-1) - -logger.error(f"PySide2 imports successful") - - -class DialogLoggerSignaller(QObject): - send_to_dialog = Signal(str) - - def __init__(self, dialog_logger): - super(DialogLoggerSignaller, self).__init__() - - self.dialog_logger = dialog_logger - - -# Independent class to handle log forwarding. Logger and qt signals both use emit method. -# This class's job is to receive the logger record and then emit the formatted message through -# DialogLoggerSignaller which is what the ProjectDialog handler listens for -class DialogLogger(logging.Handler): - - def __init__(self, log_dialog, log_level=logging.INFO, forward_log_level=logging.WARNING, - message_box_log_level=logging.ERROR): - super(DialogLogger, self).__init__() - - self.log_dialog = log_dialog - self.log_level = log_level - self.forward_log_level = forward_log_level - self.message_box_log_level = message_box_log_level - self.log_records = [] - self.formatter = logging.Formatter('%(levelname)s : %(message)s') - self.setFormatter(self.formatter) - self.signaller = DialogLoggerSignaller(self) - - def emit(self, record): - self.log_records.append(record) - if record.levelno >= self.message_box_log_level: - QMessageBox.warning(None, record.levelname, record.message) - elif record.levelno >= self.forward_log_level: - self.signaller.send_to_dialog.emit(self.format(record)) - - -class ProjectManagerDialog(QObject): - """ - Main project manager dialog is responsible for displaying the project selection list and output pane - """ - - def __init__(self, parent=None): - super(ProjectManagerDialog, self).__init__(parent) - - self.ui_path = (pathlib.Path(__file__).parent / 'ui').resolve() - self.home_folder = manifest.get_home_folder() - - self.log_display = None - self.dialog_logger = DialogLogger(self) - logger.addHandler(self.dialog_logger) - logger.setLevel(logging.INFO) - - self.dialog_logger.signaller.send_to_dialog.connect(self.handle_log_message) - self.mru_file_path = o3de_folder / 'mru.json' - - self.create_from_template_ui_file_path = self.ui_path / 'create_from_template.ui' - self.create_gem_ui_file_path = self.ui_path / 'create_gem.ui' - self.create_project_ui_file_path = self.ui_path / 'create_project.ui' - self.manage_project_gem_targets_ui_file_path = self.ui_path / 'manage_gem_targets.ui' - self.project_manager_icon_file_path = self.ui_path / 'project_manager.ico' - self.project_manager_ui_file_path = self.ui_path / 'project_manager.ui' - - self.project_manager_ui_file = QFile(self.project_manager_ui_file_path.as_posix()) - self.project_manager_ui_file.open(QFile.ReadOnly) - - loader = QUiLoader() - self.dialog = loader.load(self.project_manager_ui_file) - self.dialog.setWindowIcon(QIcon(self.project_manager_icon_file_path.as_posix())) - self.dialog.setFixedSize(self.dialog.size()) - - self.project_list_box = self.dialog.findChild(QComboBox, 'projectListBox') - self.refresh_project_list() - mru = self.get_mru_list() - if len(mru): - last_mru = pathlib.Path(mru[0]).resolve() - for this_slot in range(self.project_list_box.count()): - item_text = self.project_list_box.itemText(this_slot) - if last_mru.as_posix() in item_text: - self.project_list_box.setCurrentIndex(this_slot) - break - - self.create_project_button = self.dialog.findChild(QPushButton, 'createProjectButton') - self.create_project_button.clicked.connect(self.create_project_handler) - self.create_gem_button = self.dialog.findChild(QPushButton, 'createGemButton') - self.create_gem_button.clicked.connect(self.create_gem_handler) - self.create_template_button = self.dialog.findChild(QPushButton, 'createTemplateButton') - self.create_template_button.clicked.connect(self.create_template_handler) - self.create_from_template_button = self.dialog.findChild(QPushButton, 'createFromTemplateButton') - self.create_from_template_button.clicked.connect(self.create_from_template_handler) - - self.add_project_button = self.dialog.findChild(QPushButton, 'addProjectButton') - self.add_project_button.clicked.connect(self.add_project_handler) - self.add_gem_button = self.dialog.findChild(QPushButton, 'addGemButton') - self.add_gem_button.clicked.connect(self.add_gem_handler) - self.add_template_button = self.dialog.findChild(QPushButton, 'addTemplateButton') - self.add_template_button.clicked.connect(self.add_template_handler) - self.add_restricted_button = self.dialog.findChild(QPushButton, 'addRestrictedButton') - self.add_restricted_button.clicked.connect(self.add_restricted_handler) - - self.remove_project_button = self.dialog.findChild(QPushButton, 'removeProjectButton') - self.remove_project_button.clicked.connect(self.remove_project_handler) - self.remove_gem_button = self.dialog.findChild(QPushButton, 'removeGemButton') - self.remove_gem_button.clicked.connect(self.remove_gem_handler) - self.remove_template_button = self.dialog.findChild(QPushButton, 'removeTemplateButton') - self.remove_template_button.clicked.connect(self.remove_template_handler) - self.remove_restricted_button = self.dialog.findChild(QPushButton, 'removeRestrictedButton') - self.remove_restricted_button.clicked.connect(self.remove_restricted_handler) - - self.manage_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageRuntimeGemTargetsButton') - self.manage_project_gem_targets_button.clicked.connect(self.manage_project_gem_targets_handler) - - self.log_display = self.dialog.findChild(QLabel, 'logDisplay') - - self.ok_cancel_button = self.dialog.findChild(QDialogButtonBox, 'okCancel') - self.ok_cancel_button.accepted.connect(self.accepted_handler) - - self.dialog.show() - - def refresh_project_list(self) -> None: - projects = manifest.get_all_projects() - self.project_list_box.clear() - for this_slot in range(len(projects)): - display_name = f'{os.path.basename(os.path.normpath(projects[this_slot]))} ({projects[this_slot]})' - self.project_list_box.addItem(display_name) - self.project_list_box.setItemData(self.project_list_box.count() - 1, projects[this_slot], - Qt.ToolTipRole) - - def accepted_handler(self) -> None: - """ - Override for handling "Ok" on main project dialog to first check whether the user has selected a project and - prompt them to if not. If a project is selected will attempt to open it. - :return: None - """ - if not self.project_list_box.currentText(): - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText("Please select a project") - msg_box.exec() - return - self.launch_with_project_path(self.get_selected_project_path()) - - def get_launch_project(self) -> str: - return os.path.normpath(self.get_selected_project_path()) - - def get_executable_launch_params(self) -> list: - """ - Retrieve the necessary launch parameters to make the subprocess launch call with - this is the path - to the executable such as the Editor and the path to the selected project - :return: list of params - """ - launch_params = [executable_path, - f'-regset="/Amazon/AzCore/Bootstrap/project_path={self.get_launch_project()}"'] - return launch_params - - def launch_with_project_path(self, project_path: str) -> None: - """ - Launch the desired application given the selected project - :param project_path: Path to currently selected project - :return: None - """ - logger.info(f'Attempting to open {project_path}') - self.update_mru_list(project_path) - launch_params = self.get_executable_launch_params() - logger.info(f'Launching with params {launch_params}') - subprocess.run(launch_params, env=uninstall_env()) - - def get_selected_project_path(self) -> str: - if self.project_list_box.currentIndex() == -1: - logger.warning("No project selected") - return "" - return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole) - - def get_selected_project_name(self) -> str: - project_data = manifest.get_project_json_data(project_path=self.get_selected_project_path()) - return project_data['project_name'] - - def create_project_handler(self): - """ - Opens the Create Project pane. Retrieves a list of available templates for display - :return: None - """ - loader = QUiLoader() - self.create_project_file = QFile(self.create_project_ui_file_path.as_posix()) - - if not self.create_project_file: - logger.error(f'Failed to create project UI file at {self.create_project_file}') - return - - self.create_project_dialog = loader.load(self.create_project_file) - - if not self.create_project_dialog: - logger.error(f'Failed to load create project dialog file at {self.create_project_file}') - return - - self.create_project_ok_button = self.create_project_dialog.findChild(QDialogButtonBox, 'okCancel') - self.create_project_ok_button.accepted.connect(self.create_project_accepted_handler) - - self.create_project_template_list = self.create_project_dialog.findChild(QListView, 'projectTemplates') - self.refresh_create_project_template_list() - - self.create_project_dialog.exec() - - def create_project_accepted_handler(self) -> None: - """ - Searches the available gems list for selected gems and attempts to add each one to the current project. - Updates UI after completion. - :return: None - """ - - selected_item = self.create_project_template_list.selectionModel().currentIndex() - project_template_path = self.create_project_template_list.model().data(selected_item) - if not project_template_path: - return - - folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", - manifest.get_o3de_projects_folder().as_posix()) - folder_dialog.setFileMode(QFileDialog.AnyFile) - folder_dialog.setOptions(QFileDialog.ShowDirsOnly) - project_count = 0 - project_name = "MyNewProject" - while os.path.exists(os.path.join(engine_path, project_name)): - project_name = f"MyNewProject{project_count}" - project_count += 1 - folder_dialog.selectFile(project_name) - project_folder = None - if folder_dialog.exec(): - project_folder = folder_dialog.selectedFiles() - if project_folder: - if engine_template.create_project(project_path=project_folder[0], - template_path=project_template_path) == 0: - # Success - register.register(project_path=project_folder[0]) - self.refresh_project_list() - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Project {project_folder[0]} created.") - msg_box.exec() - return - - def create_gem_handler(self): - """ - Opens the Create Gem pane. Retrieves a list of available templates for display - :return: None - """ - loader = QUiLoader() - self.create_gem_file = QFile(self.create_gem_ui_file_path.as_posix()) - - if not self.create_gem_file: - logger.error(f'Failed to create gem UI file at {self.create_gem_file}') - return - - self.create_gem_dialog = loader.load(self.create_gem_file) - - if not self.create_gem_dialog: - logger.error(f'Failed to load create gem dialog file at {self.create_gem_file}') - return - - self.create_gem_ok_button = self.create_gem_dialog.findChild(QDialogButtonBox, 'okCancel') - self.create_gem_ok_button.accepted.connect(self.create_gem_accepted_handler) - - self.create_gem_template_list = self.create_gem_dialog.findChild(QListView, 'gemTemplates') - self.refresh_create_gem_template_list() - - self.create_gem_dialog.exec() - - def create_gem_accepted_handler(self) -> None: - """ - Searches the available gems list for selected gems and attempts to add each one to the current gem. - Updates UI after completion. - :return: None - """ - selected_item = self.create_gem_template_list.selectionModel().currentIndex() - gem_template_path = self.create_gem_template_list.model().data(selected_item) - if not gem_template_path: - return - - folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", - manifest.get_o3de_gems_folder().as_posix()) - folder_dialog.setFileMode(QFileDialog.AnyFile) - folder_dialog.setOptions(QFileDialog.ShowDirsOnly) - gem_count = 0 - gem_name = "MyNewGem" - while os.path.exists(os.path.join(engine_path, gem_name)): - gem_name = f"MyNewGem{gem_count}" - gem_count += 1 - folder_dialog.selectFile(gem_name) - gem_folder = None - if folder_dialog.exec(): - gem_folder = folder_dialog.selectedFiles() - if gem_folder: - if engine_template.create_gem(gem_path=gem_folder[0], - template_path=gem_template_path) == 0: - # Success - register.register(gem_path=gem_folder[0]) - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Gem {gem_folder[0]} created.") - msg_box.exec() - return - - def create_template_handler(self): - """ - Opens a foldr select dialog and lets the user select the source folder they want to make a template - out of, then opens a second folder select dialog to get where they want to put the template and it name - :return: None - """ - - source_folder = QFileDialog.getExistingDirectory(self.dialog, - "Select a Folder to make a template out of.", - manifest.get_o3de_folder().as_posix()) - if not source_folder: - return - - destination_template_folder_dialog = QFileDialog(self.dialog, - "Select where the template is to be created and named.", - manifest.get_o3de_templates_folder().as_posix()) - destination_template_folder_dialog.setFileMode(QFileDialog.AnyFile) - destination_template_folder_dialog.setOptions(QFileDialog.ShowDirsOnly) - destination_folder = None - if destination_template_folder_dialog.exec(): - destination_folder = destination_template_folder_dialog.selectedFiles() - if not destination_folder: - return - - if engine_template.create_template(source_path=source_folder, - template_path=destination_folder[0]) == 0: - # Success - register.register(template_path=destination_folder[0]) - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Template {destination_folder[0]} created.") - msg_box.exec() - return - - def create_from_template_handler(self): - """ - Opens the Create from_template pane. Retrieves a list of available from_templates for display - :return: None - """ - loader = QUiLoader() - self.create_from_template_file = QFile(self.create_from_template_ui_file_path.as_posix()) - - if not self.create_from_template_file: - logger.error(f'Failed to create from_template UI file at {self.create_from_template_file}') - return - - self.create_from_template_dialog = loader.load(self.create_from_template_file) - - if not self.create_from_template_dialog: - logger.error(f'Failed to load create from_template dialog file at {self.create_from_template_file}') - return - - self.create_from_template_ok_button = self.create_from_template_dialog.findChild(QDialogButtonBox, 'okCancel') - self.create_from_template_ok_button.accepted.connect(self.create_from_template_accepted_handler) - - self.create_from_template_list = self.create_from_template_dialog.findChild(QListView, 'genericTemplates') - self.refresh_create_from_template_list() - - self.create_from_template_dialog.exec() - - def create_from_template_accepted_handler(self) -> None: - """ - Searches the available gems list for selected gems and attempts to add each one to the current gem. - Updates UI after completion. - :return: None - """ - create_gem_item = self.get_selected_gem_template() - if not create_gem_item: - return - - folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", - manifest.get_o3de_gems_folder().as_posix()) - folder_dialog.setFileMode(QFileDialog.AnyFile) - folder_dialog.setOptions(QFileDialog.ShowDirsOnly) - gem_count = 0 - gem_name = "MyNewGem" - while os.path.exists(os.path.join(engine_path, gem_name)): - gem_name = f"MyNewGem{gem_count}" - gem_count += 1 - folder_dialog.selectFile(gem_name) - gem_folder = None - if folder_dialog.exec(): - gem_folder = folder_dialog.selectedFiles() - if gem_folder: - if engine_template.create_gem(gem_folder[0], create_gem_item[1]) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"gem {os.path.basename(os.path.normpath(gem_folder[0]))} created." - " Build your\nnew gem before hitting OK to launch.") - msg_box.exec() - return - - def add_project_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid project. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", - manifest.get_o3de_projects_folder().as_posix()) - if project_folder: - if register.register(project_path=project_folder) == 0: - # Success - self.refresh_project_list() - - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Added Project {project_folder}.") - msg_box.exec() - return - - def add_gem_handler(self): - """ - Open a file search dialog looking for a folder which contains a gem. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", - manifest.get_o3de_gems_folder().as_posix()) - if gem_folder: - if register.register(gem_path=gem_folder) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Added Gem {gem_folder}.") - msg_box.exec() - return - - def add_template_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid template. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", - manifest.get_o3de_templates_folder().as_posix()) - if template_folder: - if register.register(template_path=template_folder) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Added Template {template_folder}.") - msg_box.exec() - return - - def add_restricted_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid template. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", - manifest.get_o3de_restricted_folder().as_posix()) - if restricted_folder: - if register.register(restricted_path=restricted_folder) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Added Restricted {restricted_folder}.") - msg_box.exec() - return - - def remove_project_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid project. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", - manifest.get_o3de_projects_folder().as_posix()) - if project_folder: - if register.register(project_path=project_folder, remove=True) == 0: - # Success - self.refresh_project_list() - - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Removed Project {project_folder}.") - msg_box.exec() - return - - def remove_gem_handler(self): - """ - Open a file search dialog looking for a folder which contains a gem. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", - manifest.get_o3de_gems_folder().as_posix()) - if gem_folder: - if register.register(gem_path=gem_folder, remove=True) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Removed Gem {gem_folder}.") - msg_box.exec() - return - - def remove_template_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid template. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", - manifest.get_o3de_templates_folder().as_posix()) - if template_folder: - if register.register(template_path=template_folder, remove=True) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Removed Template {template_folder}.") - msg_box.exec() - return - - def remove_restricted_handler(self): - """ - Open a file search dialog looking for a folder which contains a valid template. If valid - will update the mru list with the new entry, if invalid will warn the user. - :return: None - """ - restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", - manifest.get_o3de_restricted_folder().as_posix()) - if restricted_folder: - if register.register(restricted_path=restricted_folder, remove=True) == 0: - # Success - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText(f"Removed Restricted {restricted_folder}.") - msg_box.exec() - return - - def manage_project_gem_targets_handler(self): - """ - Opens the Gem management pane. Waits for the load thread to complete if still running and displays all - active gems for the current project as well as all available gems which aren't currently active. - :return: None - """ - - if not self.get_selected_project_path(): - msg_box = QMessageBox(parent=self.dialog) - msg_box.setWindowTitle("O3DE") - msg_box.setText("Please select a project") - msg_box.exec() - return - - loader = QUiLoader() - self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix()) - - if not self.manage_project_gem_targets_file: - logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}') - return - - self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file) - - if not self.manage_project_gem_targets_dialog: - logger.error(f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}') - return - - self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Gems for Project:" - f" {self.get_selected_project_name()}") - - self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton') - self.add_gem_button.clicked.connect(self.add_project_gem_targets_handler) - - self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'availableGemTargetsList') - self.refresh_project_gem_targets_available_list() - - self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, - 'removeGemTargetsButton') - self.remove_project_gem_targets_button.clicked.connect(self.remove_project_gem_targets_handler) - - self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'enabledGemTargetsList') - self.refresh_project_gem_targets_enabled_list() - - self.manage_project_gem_targets_dialog.exec() - - - def manage_project_gem_targets_get_selected_available_gems(self) -> list: - selected_items = self.available_gem_targets_list.selectionModel().selectedRows() - return [(self.available_gem_targets_list.model().data(item)) for item in selected_items] - - def manage_project_gem_targets_get_selected_enabled_gems(self) -> list: - selected_items = self.enabled_gem_targets_list.selectionModel().selectedRows() - return [(self.enabled_gem_targets_list.model().data(item)) for item in selected_items] - - def add_project_gem_targets_handler(self) -> None: - gem_paths = manifest.get_all_gems() - for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): - for gem_path in gem_paths: - enable_gem.enable_gem_in_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) - self.refresh_project_gem_targets_available_list() - self.refresh_project_gem_targets_enabled_list() - return - self.refresh_project_gem_targets_available_list() - self.refresh_project_gem_targets_enabled_list() - - def remove_project_gem_targets_handler(self): - gem_paths = manifest.get_all_gems() - for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): - for gem_path in gem_paths: - disable_gem.disable_gem_in_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) - self.refresh_project_gem_targets_available_list() - self.refresh_project_gem_targets_enabled_list() - return - self.refresh_project_gem_targets_available_list() - self.refresh_project_gem_targets_enabled_list() - - def refresh_project_gem_targets_enabled_list(self) -> None: - enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gems = cmake.get_project_gems(project_path=self.get_selected_project_path()) - for gem_target in sorted(enabled_project_gems): - model_item = QStandardItem(gem_target) - enabled_project_gem_targets_model.appendRow(model_item) - self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model) - - - def refresh_project_gem_targets_available_list(self) -> None: - available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_gems(project_path=self.get_selected_project_path()) - all_gem_targets = manifest.get_all_gems() - for gem_target in sorted(all_gem_targets): - if gem_target not in enabled_project_gem_targets: - model_item = QStandardItem(gem_target) - available_project_gem_targets_model.appendRow(model_item) - self.available_gem_targets_list.setModel(available_project_gem_targets_model) - - - def refresh_create_project_template_list(self) -> None: - self.create_project_template_model = QStandardItemModel() - for project_template_path in manifest.get_project_templates(): - model_item = QStandardItem(project_template_path) - self.create_project_template_model.appendRow(model_item) - self.create_project_template_list.setModel(self.create_project_template_model) - - def refresh_create_gem_template_list(self) -> None: - self.create_gem_template_model = QStandardItemModel() - for gem_template_path in manifest.get_gem_templates(): - model_item = QStandardItem(gem_template_path) - self.create_gem_template_model.appendRow(model_item) - self.create_gem_template_list.setModel(self.create_gem_template_model) - - def refresh_create_from_template_list(self) -> None: - self.create_from_template_model = QStandardItemModel() - for generic_template_path in manifest.get_generic_templates(): - model_item = QStandardItem(generic_template_path) - self.create_from_template_model.appendRow(model_item) - self.create_from_template_list.setModel(self.create_from_template_model) - - def update_mru_list(self, used_project: str) -> None: - """ - Promote a supplied project name to the "most recent" in a given MRU list. - :param used_project: path to project to promote - :param file_path: path to mru list file - :return: None - """ - used_project = os.path.normpath(used_project) - if not os.path.exists(os.path.dirname(self.mru_file_path)): - os.makedirs(os.path.dirname(self.mru_file_path), exist_ok=True) - mru_data = {} - try: - with open(self.mru_file_path, 'r') as mru_file: - mru_data = json.loads(mru_file.read()) - except FileNotFoundError: - pass - except json.JSONDecodeError: - pass - - recent_list = mru_data.get('Projects', []) - recent_list = [item for item in recent_list if item.get('Path') != used_project and - self.is_project_folder(item.get('Path'))] - - new_list = [{'Path': used_project}] - new_list.extend(recent_list) - - mru_data['Projects'] = new_list - try: - with open(self.mru_file_path, 'w') as mru_file: - mru_file.write(json.dumps(mru_data, indent=1)) - except PermissionError as e: - logger.warning(f"Failed to write {self.mru_file_path} with error {e}") - - def get_mru_list(self) -> List[str]: - """ - Retrieve the current MRU list. Does not perform validation that the projects still appear valid - :return: list of full path strings to project folders - """ - if not os.path.exists(os.path.dirname(self.mru_file_path)): - return [] - try: - with open(self.mru_file_path, 'r') as mru_file: - mru_data = json.loads(mru_file.read()) - except FileNotFoundError: - return [] - except json.JSONDecodeError: - logger.error(f'MRU list at {self.mru_file_path} is not valid JSON') - return [] - - recent_list = mru_data.get('Projects', []) - return [item.get('Path') for item in recent_list if item.get('Path') is not None] - - @Slot(str) - def handle_log_message(self, message: str) -> None: - """ - Signal handler for messages from the logger. Displays the most recent warning/error - :param message: formatted log message from DialogLoggerSignaller - :return: - """ - if not self.log_display: - return - self.log_display.setText(message) - self.log_display.setToolTip(message) - - -if __name__ == "__main__": - dialog_app = QApplication(sys.argv) - my_dialog = ProjectManagerDialog() - dialog_app.exec_() - sys.exit(0) diff --git a/scripts/project_manager/pyside.py b/scripts/project_manager/pyside.py deleted file mode 100755 index 80bf327f9b..0000000000 --- a/scripts/project_manager/pyside.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import os -import logging - -from pathlib import Path - -logger = logging.getLogger() - -pyside_initialized = False -old_env = os.environ.copy() - -# Helper to extend OS PATH for pyside to locate our QT binaries based on our build folder -def add_pyside_environment(bin_path): - if is_pyside_ready(): - # No need to reinitialize currently - logger.info("Pyside environment already initialized") - return - global old_env - old_env = os.environ.copy() - binaries_path = Path(os.path.normpath(bin_path)) - platforms_path = binaries_path.joinpath("platforms") - logger.info(f'Adding binaries path {binaries_path}') - os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = str(platforms_path) - - path = os.environ['PATH'] - - new_path = os.pathsep.join([str(binaries_path), str(platforms_path), path]) - os.environ['PATH'] = new_path - - global pyside_initialized - pyside_initialized = True - - -def is_pyside_ready(): - return pyside_initialized - - -def is_configuration_valid(workspace): - return os.path.basename(workspace.paths.build_directory()) != "debug" - - -def uninstall_env(): - if not is_pyside_ready(): - logger.warning("Pyside not initialized") - return os.environ - - global old_env - if old_env.get("QT_QPA_PLATFORM_PLUGIN_PATH"): - old_env.pop("QT_QPA_PLATFORM_PLUGIN_PATH") - os.environ = old_env - return old_env diff --git a/scripts/project_manager/tests/__init__.py b/scripts/project_manager/tests/__init__.py deleted file mode 100755 index 4d5680a30d..0000000000 --- a/scripts/project_manager/tests/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# diff --git a/scripts/project_manager/tests/test_projects.py b/scripts/project_manager/tests/test_projects.py deleted file mode 100755 index d073cf6c7a..0000000000 --- a/scripts/project_manager/tests/test_projects.py +++ /dev/null @@ -1,255 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - - -import pytest -''' -import os -import sys -import tempfile -import logging -import pathlib -from unittest.mock import MagicMock - -logger = logging.getLogger() - -# Code lives one folder above -project_manager_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) -sys.path.append(project_manager_path) - -from pyside import add_pyside_environment, is_configuration_valid -from ly_test_tools import WINDOWS - -sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))) -executable_path = '' -from cmake.Tools import registration -from cmake.Tools import engine_template - - -class ProjectHelper: - def __init__(self): - self._temp_directory = pathlib.Path(tempfile.TemporaryDirectory().name).resolve() - self._temp_directory.mkdir(parents=True, exist_ok=True) - - self.home_path = self._temp_directory - registration.override_home_folder = self.home_path - self.engine_path = registration.get_this_engine_path() - if registration.register(engine_path=self.engine_path): - assert True, f"Failed to register the engine." - - if registration.register_shipped_engine_o3de_objects(): - assert True, f"Failed to register shipped engine objects." - - self.projects_folder = registration.get_o3de_projects_folder() - if not self.projects_folder.is_dir(): - assert True - - self.application = None - self.dialog = None - - def create_empty_projects(self): - self.project_1_dir = self.projects_folder / "Project1" - if engine_template.create_project(project_manager_path=self.project_1_dir): - assert True, f"Failed to create Project1." - - self.project_2_dir = self.projects_folder / "Project2" - if engine_template.create_project(project_manager_path=self.project_2_dir): - assert True, f"Failed to create Project2." - - self.project_3_dir = self.projects_folder / "Project3" - if engine_template.create_project(project_manager_path=self.project_3_dir): - assert True, f"Failed to create Project3." - - self.invalid_project_dir = self.projects_folder / "InvalidProject" - self.invalid_project_dir.mkdir(parents=True, exist_ok=True) - - def setup_dialog_test(self, workspace): - add_pyside_environment(workspace.paths.build_directory()) - - if not is_configuration_valid(workspace): - # This is essentially skipif debug. Our debug tests use our profile version of python, but that means we'd - # need to use the profile version of PySide which works with the profile QT libs which aren't in the debug - # folder we've built. - return None - - from PySide2.QtWidgets import QApplication, QMessageBox - - if QApplication.instance(): - self.application = QApplication.instance() - else: - self.application = QApplication(sys.argv) - assert self.application - - from projects import ProjectManagerDialog - - try: - self.dialog = ProjectManagerDialog(settings_folder=self.home_path) - return self.dialog - except Exception as e: - logger.error(f'Failed to create ProjectManagerDialog with error {e}') - return None - - def create_project_from_template(self, project_name) -> bool: - """ - Uses the dialog to create a temporary project based on the first template found - :param project_name: Name of project to create. Will be created under temp_project_root - :return: True for Success, False for failure - """ - from PySide2.QtWidgets import QWidget, QFileDialog - from projects import ProjectManagerDialog - - QWidget.exec = MagicMock() - self.dialog.create_project_handler() - QWidget.exec.assert_called_once() - - assert len(self.dialog.project_templates), 'Failed to find any project templates' - ProjectManagerDialog.get_selected_project_template = MagicMock(return_value=self.dialog.project_templates[0]) - - QFileDialog.exec = MagicMock() - create_project_path = self.projects_folder / project_name - QFileDialog.selectedFiles = MagicMock(return_value=[create_project_path]) - self.dialog.create_project_accepted_handler() - if create_project_path.is_dir(): - assert True, f"Expected project creation folder not found at {create_project_path}" - - if QWidget.exec.call_count == 2: - assert True, "Message box confirming project creation failed to show" - - -@pytest.fixture -def project_helper(): - return ProjectHelper() - - -@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent -def test_logger_handler(workspace, project_helper): - my_dialog = project_helper.setup_dialog_test(workspace) - if not my_dialog: - return - - from PySide2.QtWidgets import QMessageBox - QMessageBox.warning = MagicMock() - logger.error(f'Testing logger') - QMessageBox.warning.assert_called_once() - - -@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent -def test_mru_list(workspace, project_helper): - my_dialog = project_helper.setup_dialog_test(workspace) - if not my_dialog: - return - - project_helper.create_empty_projects() - - from PySide2.QtWidgets import QMessageBox - - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 0, f'MRU list unexpectedly had entries: {mru_list}' - - QMessageBox.warning = MagicMock() - my_dialog.add_project(project_helper.invalid_project_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 0, f'MRU list unexpectedly added an invalid project : {mru_list}' - QMessageBox.warning.assert_called_once() - - my_dialog.add_project(project_helper.project_1_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 1, f'MRU list failed to add project at {project_helper.project_1_dir}' - - my_dialog.add_project(project_helper.project_1_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}' - - my_dialog.update_mru_list(project_helper.project_1_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}' - - my_dialog.add_project(project_helper.project_2_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 2, f'MRU list failed to add project at {project_helper.project_2_dir}' - - assert mru_list[0] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't first item" - assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item" - - my_dialog.update_mru_list(project_helper.project_1_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 2, f'MRU list added wrong items {mru_list}' - assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item" - assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item" - - my_dialog.add_project(project_helper.invalid_project_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 2, f'MRU list added invalid item {mru_list}' - assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item" - assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item" - - my_dialog.add_project(project_helper.project_3_dir) - mru_list = my_dialog.get_mru_list() - assert len(mru_list) == 3, f'MRU list failed to add {project_helper.project_3_dir} : {mru_list}' - assert mru_list[0] == project_helper.project_3_dir, f"{project_helper.project_3_dir} wasn't first item" - assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item" - assert mru_list[2] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't third item" - - -@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent -def test_create_project(workspace, project_helper): - my_dialog = project_helper.setup_dialog_test(workspace) - if not my_dialog: - return - - project_helper.create_project_from_template("TestCreateProject") - - -@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent -def test_add_remove_gems(workspace, project_helper): - my_dialog = project_helper.setup_dialog_test(workspace) - if not my_dialog: - return - - my_project_name = "TestAddRemoveGems" - - project_helper.create_project_from_template(project_manager_path=my_project_name) - my_project_path = project_helper.projects_folder / my_project_name - - from PySide2.QtWidgets import QWidget, QFileDialog - from projects import ProjectManagerDialog - - assert my_dialog.get_selected_project_path() == my_project_path, "TestAddRemoveGems project not selected" - QWidget.exec = MagicMock() - my_dialog.manage_gems_handler() - assert my_dialog.manage_gem_targets_dialog, "No gem management dialog created" - QWidget.exec.assert_called_once() - - if not len(my_dialog.all_gems_list): - assert True, 'Failed to find any gems' - - my_test_gem_path = my_dialog.all_gems_list[0] - gem_data = registration.get_gem_data(my_test_gem_path) - my_test_gem_selection = (my_test_gem_name, my_test_gem_path) - ProjectManagerDialog.get_selected_add_gems = MagicMock(return_value=[my_test_gem_selection]) - - assert my_test_gem_name, "No Name set in test gem" - assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} already in project gem list' - - my_dialog.add_gems_handler() - assert my_test_gem_name in my_dialog.project_gem_list, f'Gem {my_test_gem_name} failed to add to gem list' - - ProjectManagerDialog.get_selected_project_gems = MagicMock(return_value=[my_test_gem_name]) - my_dialog.remove_gems_handler() - assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} still in project gem list' -''' - -def test_project_place_holder(): - pass \ No newline at end of file diff --git a/scripts/project_manager/tests/test_pyside.py b/scripts/project_manager/tests/test_pyside.py deleted file mode 100755 index c9be313f2b..0000000000 --- a/scripts/project_manager/tests/test_pyside.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import pytest -import sys -import os - -pyside_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) -sys.path.append(pyside_path) - -from pyside import add_pyside_environment, is_pyside_ready, is_configuration_valid - -from ly_test_tools import WINDOWS - -import logging -logger = logging.getLogger() - -@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently") -@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent -def test_add_pyside_environment(workspace): - import_failed = False - try: - import PySide2 - except ImportError: - import_failed = True - - if not import_failed: - cur_path = sys.path - logger.warning(f"Expected to fail initial import but passed. Sys path was {cur_path}") - - assert is_pyside_ready() is False, "Expected pyside not to be initialized yet" - add_pyside_environment(workspace.paths.build_directory()) - assert is_pyside_ready() is True, "Expected pyside to be initialized yet" - - try: - import PySide2 - if not is_configuration_valid(workspace): - return - from PySide2.QtWidgets import QApplication - except ImportError as e: - assert False, f"Failed to import PySide2 with error {e}" - try: - from PySide2.QtWidgets import QApplication - except ImportError as e: - assert False, f"Failed to import QApplication from PySide2.QtWidgets with error {e}" - diff --git a/scripts/project_manager/ui/create_from_template.ui b/scripts/project_manager/ui/create_from_template.ui deleted file mode 100644 index b6a8740594..0000000000 --- a/scripts/project_manager/ui/create_from_template.ui +++ /dev/null @@ -1,94 +0,0 @@ - - - createFromTemplateDialog - - - - 0 - 0 - 467 - 288 - - - - Create From Template - - - - - 50 - 250 - 400 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 449 - 221 - - - - QAbstractItemView::SingleSelection - - - - - - 10 - 0 - 300 - 16 - - - - Available Templates - - - - - - - okCancel - accepted() - createFromTemplateDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - okCancel - rejected() - createFromTemplateDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/scripts/project_manager/ui/create_gem.ui b/scripts/project_manager/ui/create_gem.ui deleted file mode 100644 index 5a5fd14a6d..0000000000 --- a/scripts/project_manager/ui/create_gem.ui +++ /dev/null @@ -1,94 +0,0 @@ - - - createGemDialog - - - - 0 - 0 - 467 - 288 - - - - Create Gem - - - - - 50 - 250 - 400 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 449 - 221 - - - - QAbstractItemView::SingleSelection - - - - - - 10 - 0 - 300 - 16 - - - - Available Templates - - - - - - - okCancel - accepted() - createGemDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - okCancel - rejected() - createGemDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/scripts/project_manager/ui/create_project.ui b/scripts/project_manager/ui/create_project.ui deleted file mode 100644 index 67a13325b0..0000000000 --- a/scripts/project_manager/ui/create_project.ui +++ /dev/null @@ -1,94 +0,0 @@ - - - createProjectDialog - - - - 0 - 0 - 467 - 288 - - - - Create Project - - - - - 50 - 250 - 400 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 449 - 221 - - - - QAbstractItemView::SingleSelection - - - - - - 10 - 0 - 300 - 16 - - - - Available Templates - - - - - - - okCancel - accepted() - createProjectDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - okCancel - rejected() - createProjectDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/scripts/project_manager/ui/manage_gem_targets.ui b/scripts/project_manager/ui/manage_gem_targets.ui deleted file mode 100644 index ea9e607d42..0000000000 --- a/scripts/project_manager/ui/manage_gem_targets.ui +++ /dev/null @@ -1,165 +0,0 @@ - - - manageGemTargetsDialog - - - - 0 - 0 - 702 - 297 - - - - Manage Gem Targets - - - - - 310 - 260 - 71 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - 440 - 50 - 250 - 221 - - - - - 0 - 0 - - - - QAbstractItemView::ExtendedSelection - - - - - - 10 - 50 - 250 - 221 - - - - QAbstractItemView::ExtendedSelection - - - - - - 440 - 30 - 251 - 16 - - - - Available Gem Targets - - - - - - 10 - 30 - 251 - 16 - - - - Enabled Gem Targets - - - - - - 264 - 130 - 171 - 23 - - - - Remove Gem Targets >> - - - - - - 264 - 100 - 171 - 23 - - - - << Add Gem Targets - - - - - - 10 - 5 - 400 - 21 - - - - Adding new Gem Targets may require rebuilding - - - - - - - close - accepted() - manageGemTargetsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - close - rejected() - manageGemTargetsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/scripts/project_manager/ui/project_manager.ico b/scripts/project_manager/ui/project_manager.ico deleted file mode 100644 index 597266946a..0000000000 --- a/scripts/project_manager/ui/project_manager.ico +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:113be7ded1969e0d535722382b6d3730eed052a10430cf23804ae7f20414b999 -size 108278 diff --git a/scripts/project_manager/ui/project_manager.ui b/scripts/project_manager/ui/project_manager.ui deleted file mode 100644 index 6b3b5f758c..0000000000 --- a/scripts/project_manager/ui/project_manager.ui +++ /dev/null @@ -1,407 +0,0 @@ - - - Dialog - - - - 0 - 0 - 712 - 395 - - - - - 1 - 0 - - - - O3DE - - - Select and manage your projects for O3DE - - - - - 540 - 360 - 161 - 31 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 30 - 691 - 31 - - - - Current project to launch or manage gems for. - - - - - - 10 - 10 - 47 - 13 - - - - Project - - - - - - 270 - 220 - 431 - 141 - - - - QFrame::Panel - - - QFrame::Sunken - - - - - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - 10 - 70 - 241 - 151 - - - - Create - - - - - 10 - 110 - 221 - 31 - - - - Create a new O3DE object from a pre configured template. - - - Create From Template - - - - - - 10 - 20 - 221 - 31 - - - - Create a new O3DE object from a pre configured template. - - - Create Project - - - - - - 11 - 50 - 221 - 31 - - - - Create a new O3DE object from a pre configured template. - - - Create Gem - - - - - - 11 - 80 - 221 - 31 - - - - Create a new O3DE object from a pre configured template. - - - Create Template - - - - - - - 260 - 70 - 451 - 141 - - - - Registration - - - - - 10 - 80 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Add Template - - - - - - 10 - 20 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Add Project - - - - - - 10 - 50 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Add Gem - - - - - - 10 - 110 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Add Restricted - - - - - - 230 - 110 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Remove Restricted - - - - - - 230 - 20 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Remove Project - - - - - - 230 - 50 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Remove Gem - - - - - - 230 - 80 - 211 - 31 - - - - Browse for an existing O3DE project. - - - Remove Template - - - - - - - 10 - 230 - 241 - 121 - - - - Manage Project - - - - - 10 - 80 - 221 - 31 - - - - Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. - - - Manage Server Gem Targets - - - - - - 10 - 50 - 221 - 31 - - - - Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. - - - Manage Tool Gem Targets - - - - - - 10 - 20 - 221 - 31 - - - - Add or remove gems from your selected project. Gems add and remove additional assets and features to projects. - - - Manage Runtime Gem Targets - - - - - - - - okCancel - accepted() - Dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - okCancel - rejected() - Dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - From 1b8810b9631a7cd42e141fa23f2cf6bbd1ca1ef0 Mon Sep 17 00:00:00 2001 From: Eric Phister <52085794+amzn-phist@users.noreply.github.com> Date: Thu, 3 Jun 2021 14:52:21 -0500 Subject: [PATCH 074/153] Remove Project namespace from project template (#1124) In the enabled_gems.cmake file, can remove the Project:: namespace on the project module because it's treated the same as a Gem module now. --- Templates/DefaultProject/Template/Code/enabled_gems.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Templates/DefaultProject/Template/Code/enabled_gems.cmake b/Templates/DefaultProject/Template/Code/enabled_gems.cmake index dfb7d93233..ec45be0743 100644 --- a/Templates/DefaultProject/Template/Code/enabled_gems.cmake +++ b/Templates/DefaultProject/Template/Code/enabled_gems.cmake @@ -10,7 +10,7 @@ # {END_LICENSE} set(ENABLED_GEMS - Project::${Name} + ${Name} Atom_AtomBridge Camera CameraFramework From 1245e0b327b3bbeb05ab4f181fd1403cbeaa908e Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 15:02:03 -0500 Subject: [PATCH 075/153] Adding Tools and Builders alias to the DccScriptingInterface gem targets (#1087) * Adding a Tools and Builders variant to the DccScriptingInterface gem target to allow it to be used as a gem in the AtomTest project * Adding support to ly_create_alias to be able to specify an alias with no dependencies Updated the SettingsRegistry.cmake generation code to support generating a Gem target entry in the cmake_dependencies.*.setreg file when an interface library with no dependencies is parsed --- .../DccScriptingInterface/Code/CMakeLists.txt | 10 ++++++++ cmake/Gems.cmake | 10 ++++---- cmake/SettingsRegistry.cmake | 23 +++++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt index 76cbf6546d..bad0d743c7 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Code/CMakeLists.txt @@ -9,6 +9,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +if(NOT PAL_TRAIT_BUILD_HOST_TOOLS) + return() +endif() + ly_add_target( NAME DccScriptingInterface.Static STATIC NAMESPACE Gem @@ -38,3 +42,9 @@ ly_add_target( PRIVATE Gem::DccScriptingInterface.Static ) + +# Any 'tool' type applications should use Gem::DccScriptingInterface.Editor: +ly_create_alias(NAME DccScriptingInterface.Tools NAMESPACE Gem TARGETS Gem::DccScriptingInterface.Editor) +# Add an empty 'builders' alias to allow the DccScriptInterface root gem path to be added to the generated +# cmake_dependencies..assetprocessor.setreg to allow the asset scan folder for it to be added +ly_create_alias(NAME DccScriptingInterface.Builders NAMESPACE Gem) diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake index d418d5dcd1..169210d991 100644 --- a/cmake/Gems.cmake +++ b/cmake/Gems.cmake @@ -29,9 +29,6 @@ function(ly_create_alias) message(FATAL_ERROR "Provide the namespace of the alias to create using the NAMESPACE keyword") endif() - if (NOT ly_create_alias_TARGETS) - message(FATAL_ERROR "Provide the name of the targets the alias be associated with, using the TARGETS keyword") - endif() if(TARGET ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}) message(FATAL_ERROR "Target already exists, cannot create an alias for it: ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}\n" @@ -78,8 +75,11 @@ function(ly_create_alias) list(APPEND final_targets ${de_aliased_target_name}) endforeach() - ly_parse_third_party_dependencies("${final_targets}") - ly_add_dependencies(${ly_create_alias_NAME} ${final_targets}) + # add_dependencies must be called with at least one dependent target + if(final_targets) + ly_parse_third_party_dependencies("${final_targets}") + ly_add_dependencies(${ly_create_alias_NAME} ${final_targets}) + endif() # now add the final alias: add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME}) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 4d932601b4..d7ef91d284 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -25,14 +25,15 @@ set(gems_json_template [[ @target_gem_dependencies_names@ } } -}]] +} +]] ) -set(gem_module_template [[ - "@stripped_gem_target@": - { - "Modules":["$"], - "SourcePaths":["@gem_module_root_relative_to_engine_root@"] - }]] + string(APPEND gem_module_template +[=[ "@stripped_gem_target@":]=] "\n" +[=[ {]=] "\n" +[=[$<$,INTERFACE_LIBRARY>>: "Modules":["$"]]=] "$\n>" +[=[ "SourcePaths":["@gem_module_root_relative_to_engine_root@"]]=] "\n" +[=[ }]=] ) #!ly_get_gem_load_dependencies: Retrieves the list of "load" dependencies for a target @@ -161,10 +162,12 @@ function(ly_delayed_generate_settings_registry) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() + get_property(has_manually_added_dependencies TARGET ${gem_target} PROPERTY MANUALLY_ADDED_DEPENDENCIES SET) get_target_property(target_type ${gem_target} TYPE) - if (target_type STREQUAL "INTERFACE_LIBRARY") - # don't use interface libraries here, we only want ones which produce actual binaries. - # we have still already recursed into their dependencies - they'll show up later. + if (target_type STREQUAL "INTERFACE_LIBRARY" AND has_manually_added_dependencies) + # don't use interface libraries here, we only want ones which produce actual binaries unless the target + # is empty. We have still already recursed into their dependencies - they'll show up later. + # When the target has no dependencies however we want to add the gem root path to the generated setreg continue() endif() From 0a9d6f5f0f54419b8bab035379b1f631c97a4a53 Mon Sep 17 00:00:00 2001 From: chcurran Date: Thu, 3 Jun 2021 13:13:22 -0700 Subject: [PATCH 076/153] Bug fixes and improvements brought over from demo work. * Generic Multi Function Call ability added to extensible nodes * Code gen improvements, including allowing for more manually codewritten extension of codegen facilities * CVAR to disable automatic update of deprecated node * Fixed variable sorting error that can apply to parser/runtime added variables * Made Edit/SerializeContext ClassBuilder public, as it was needlessly private * Fixed dangerous Datum::GetValueAddress(), it now checks for an empty storage AZSTd::any, as does Datum::Empty() --- .../AzCore/AzCore/Serialization/EditContext.h | 5 +- .../AzCore/Serialization/SerializeContext.h | 10 +- .../Code/Editor/Components/EditorGraph.cpp | 5 +- .../AutoGen/ScriptCanvasNodeable_Header.jinja | 40 +- .../AutoGen/ScriptCanvasNodeable_Source.jinja | 160 +- .../ScriptCanvas_Nodeable_Macros.jinja | 5 +- .../Code/Include/ScriptCanvas/Core/Core.h | 1 - .../Code/Include/ScriptCanvas/Core/Datum.cpp | 8 +- .../Code/Include/ScriptCanvas/Core/Datum.h | 2 +- .../Code/Include/ScriptCanvas/Core/Node.cpp | 11 +- .../Code/Include/ScriptCanvas/Core/Node.h | 2 + .../Include/ScriptCanvas/Core/NodeableNode.h | 2 + .../Code/Include/ScriptCanvas/Core/PureData.h | 2 + .../Grammar/AbstractCodeModel.cpp | 193 +- .../ScriptCanvas/Grammar/AbstractCodeModel.h | 2 + .../ScriptCanvas/Grammar/ParsingUtilities.cpp | 10 +- .../Include/ScriptCanvas/Grammar/Primitives.h | 28 + .../Grammar/PrimitivesExecution.cpp | 38 +- .../Grammar/PrimitivesExecution.h | 8 + .../Include/ScriptCanvas/Results/ErrorText.h | 6 + ...UnitTest_RunAllTransformNodes.scriptcanvas | 9124 +++++++---------- 21 files changed, 4416 insertions(+), 5246 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h index ed19130579..394a6f047c 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/EditContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/EditContext.h @@ -127,13 +127,14 @@ namespace AZ */ class EditContext { + public: /// @cond EXCLUDE_DOCS class ClassBuilder; class EnumBuilder; using ClassInfo = ClassBuilder; ///< @deprecated Use EditContext::ClassBuilder using EnumInfo = EnumBuilder; ///< @deprecated Use EditContext::EnumBuilder /// @endcond - public: + AZ_CLASS_ALLOCATOR(EditContext, SystemAllocator, 0); /** @@ -186,6 +187,7 @@ namespace AZ * look at the unit tests and example to see use cases. * */ + public: class ClassBuilder { friend EditContext; @@ -399,6 +401,7 @@ namespace AZ EnumBuilder* Value(const char* name, E value); }; + private: typedef AZStd::list ClassDataListType; typedef AZStd::unordered_map EnumDataMapType; diff --git a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h index 6806232337..279ce01039 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h +++ b/Code/Framework/AzCore/AzCore/Serialization/SerializeContext.h @@ -101,6 +101,9 @@ namespace AZ class SerializeContext : public ReflectContext { + static const unsigned int VersionClassDeprecated = (unsigned int)-1; + + public: /// @cond EXCLUDE_DOCS friend class EditContext; class ClassBuilder; @@ -108,9 +111,6 @@ namespace AZ /// @endcond class EnumBuilder; - static const unsigned int VersionClassDeprecated = (unsigned int)-1; - - public: class ClassData; struct EnumerateInstanceCallContext; struct ClassElement; @@ -1131,6 +1131,7 @@ namespace AZ * ->Version(3,&MyVersionConverter) * ->Field("data",&MyStruct::m_data); */ + public: class ClassBuilder { friend class SerializeContext; @@ -1330,7 +1331,8 @@ namespace AZ AZStd::vector* m_currentAttributes = nullptr; }; - EditContext* m_editContext; ///< Pointer to optional edit context. + private: + EditContext* m_editContext; ///< Pointer to optional edit context. UuidToClassMap m_uuidMap; ///< Map for all class in this serialize context AZStd::unordered_multimap m_classNameToUuid; /// Map all class names to their uuid AZStd::unordered_multimap m_uuidGenericMap; ///< Uuid to ClassData map of reflected classes with GenericTypeInfo diff --git a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp index 6f28cbfe19..616be11dd0 100644 --- a/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Components/EditorGraph.cpp @@ -91,7 +91,8 @@ AZ_POP_DISABLE_WARNING #include #include -//// + AZ_CVAR(bool, g_disableDeprecatedNodeUpdates, false, {}, AZ::ConsoleFunctorFlags::Null, + "Disables automatic update attempts of deprecated nodes, so that graphs that require and update can be viewed in their original form"); namespace EditorGraphCpp { @@ -3642,7 +3643,7 @@ namespace ScriptCanvasEditor if (scriptCanvasNode) { - if (scriptCanvasNode->IsDeprecated()) + if (scriptCanvasNode->IsDeprecated() && !g_disableDeprecatedNodeUpdates) { ScriptCanvas::NodeConfiguration nodeConfig = scriptCanvasNode->GetReplacementNodeConfiguration(); if (nodeConfig.IsValid()) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Header.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Header.jinja index 202fad5b60..313fd196b0 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Header.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Header.jinja @@ -22,6 +22,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #pragma once +#include +#include +#include +#include + #include #include @@ -43,6 +48,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. {% endif %} {% endif %} +{%- set attribute_Base = Class.attrib['Base'] %} +{% if not Class.attrib['Base'] is defined %} +{% set attribute_Base = "ScriptCanvas::Nodeable" %} +{% endif %} + {% if attribute_Namespace is defined %} namespace {{attribute_Namespace}} { @@ -66,6 +76,9 @@ namespace {{attribute_Namespace}} public: \ AZ_RTTI({{className}}, "{{nodeableClassName|createHashGuid}}"{% if Class.attrib['Base'] is defined %}, {{ Class.attrib['Base'] }}{% endif %}); \ static void Reflect(AZ::ReflectContext* reflection); \ + static void ExtendReflectionSerialize([[maybe_unused]] AZ::SerializeContext::ClassBuilder* builder){% if Class.attrib['ExtendReflectionSerialize'] is defined %};{% else %}{}{% endif %} \ + static void ExtendReflectionEdit([[maybe_unused]] AZ::EditContext::ClassBuilder* builder){% if Class.attrib['ExtendReflectionEdit'] is defined %};{% else %}{}{% endif %} \ + static void ExtendReflectionBehavior([[maybe_unused]] AZ::BehaviorContext::ClassBuilder<{{className}}>* builder){% if Class.attrib['ExtendReflectionBehavior'] is defined %};{% else %}{}{% endif %} \ static const char* GetDescription() { return "{{ macros.GetAttributeAsString(Class.attrib, 'Description') }}"; } \ ScriptCanvas::NodePropertyInterface* GetPropertyInterface(AZ::Crc32 propertyId) override; \ bool IsActive() const override { return false; } \ @@ -83,13 +96,33 @@ public: \ AZ_COMPONENT({{nodeableNodeName}}, {% if Class.attrib['NodeableUuid'] is defined %}"{{Class.attrib['NodeableUuid']}}"{% else %}"{{nodeableNodeName|createHashGuid}}"{% endif %}, ScriptCanvas::Nodes::NodeableNode); static void Reflect(AZ::ReflectContext* context); + + static void ExtendReflectionSerialize([[maybe_unused]] AZ::SerializeContext::ClassBuilder* builder){% if Class.attrib['ExtendReflectionSerialize'] is defined %};{% else %}{}{% endif %} + + static void ExtendReflectionEdit([[maybe_unused]] AZ::EditContext::ClassBuilder* builder){% if Class.attrib['ExtendReflectionEdit'] is defined %};{% else %}{}{% endif %} + + static void ExtendReflectionBehavior([[maybe_unused]] AZ::BehaviorContext::ClassBuilder<{{nodeableNodeName}}>* builder){% if Class.attrib['ExtendReflectionBehavior'] is defined %};{% else %}{}{% endif %} + void ConfigureSlots() override; + +{% if Class.attrib['ExtendConfigureSlots'] is defined %} + void ExtendConfigureSlots([[maybe_unused]] SlotExecution::Ins& ins, [[maybe_unused]] SlotExecution::Outs& latents); + +{% else %} + /* no slot configuration extension, Use Class attribute 'ExtendConfigureSlots' to extend them */ + +{% endif %} void ConfigureVisualExtensions() override; + size_t GenerateFingerprint() const override; -{% if Class.attrib['EntryPoint'] is defined and Class.attrib['EntryPoint'] == "true" %} + +{% if Class.attrib['EntryPoint'] is defined and Class.attrib['EntryPoint'] == "true" %} bool IsEntryPoint() const override { return true; } -{% endif %} + +{% endif %} {{nodeableNodeName}}(); + + {{Class.attrib['NodeDeclarations']}} }; } {% endif %} @@ -100,6 +133,5 @@ public: \ {{ macros.ReportErrors() }} - {% endfor %} -{% endfor %} +{% endfor %} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja index 71681ed73b..b977daf43b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvasNodeable_Source.jinja @@ -19,15 +19,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include -#include - #include #include #include #include - #include {% for xml in dataFiles %} @@ -47,13 +42,18 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. {%- set attribute_Category = Class.attrib['Category'] %} {%- set attribute_Uuid = Class.attrib['Uuid'] %} {%- set attribute_Icon = Class.attrib['Icon'] %} -{%- set attribute_Base = Class.attrib['Base'] %} {%- set attribute_GeneratePropertyFriend = Class.attrib['GeneratePropertyFriend'] %} {%- set attribute_Version = Class.attrib['Version'] %} {%- set attribute_VersionConverter = Class.attrib['VersionConverter'] %} {%- set attribute_EventHandler = Class.attrib['EventHandler'] %} {%- set attribute_Deprecated = Class.attrib['Deprecated'] %} + +{%- set attribute_Base = Class.attrib['Base'] %} +{% if not Class.attrib['Base'] is defined %} +{% set attribute_Base = "ScriptCanvas::Nodeable" %} +{% endif %} + {% set attribute_Namespace = undefined %} {%- if Class.attrib['Namespace'] is defined %} {% if Class.attrib['Namespace'] != "None" %} @@ -95,19 +95,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. {{CollectDisplayGroups('Output')}} {{CollectDisplayGroups('Parameter')}} -{# FOR DEBUGGING / DIAGNOSTIC - -// Standalone (No DisplayGroup) {{ global_standaloneTagMap }} -{% for key, value in global_standaloneTagMap.items() %} -// {{key}} : {{value}} -{% endfor %} - -// DisplayGrouped {{ global_displayGroupMap }} -{% for key, value in global_displayGroupMap.items() %} -// {{key}} : {{value}} -{% endfor %} -#} - {# ----------------------------------------------------------------------------------------- #} {% if attribute_Namespace is defined %} @@ -115,33 +102,6 @@ namespace {{attribute_Namespace}} { {% endif %} -{# Standard "In" function } -{{nodemacro.FunctionSignature(attribute_QualifiedName, Class)}} -{ -{%- for parameter in Class.findall('Parameter') -%} -{% if parameter.attrib['Input'] is defined and parameter.attrib['Input'] == "True" %} - -// this->{{parameter.attrib['Name']}} = arg{{loop.index0}}; - -{%- endif -%} -{% endfor %} - -{% set returnNames = [] %} -{% set returnTypes = [] %} -{%- for return in Class.findall('Parameter') -%} -{%- if return.attrib['Output'] is defined and return.attrib['Output'] == "True" -%} -{% if returnTypes.append(return.attrib['Type']) %}{% endif %} -{% if returnNames.append("this->" + return.attrib['Name']) %}{% endif %} -{%- endif -%} -{%- endfor -%} - -{% if returnNames|length() == 1 %} -return {{returnNames[0]}}; -{% elif returnNames|length() > 1 %} - return AZStd::tuple<{{returnTypes|join(", ")}}>({{returnNames|join(", ")}}); -{% endif %} -} -#} {%- set nodeableNodeName = attribute_Name + 'Node' %} {% set list_outputs = [] %} {% for output in Class.iter('Output') %} @@ -156,43 +116,81 @@ return {{returnNames[0]}}; {% for item in Class.iter('Output') %} {% if item.attrib['DisplayGroup'] is defined %}{% set displayGroup = item.attrib['DisplayGroup'] %}{% endif %} {% endfor %} +{% set branches = [] %} +{% for method in Class.findall('Input') %} +{% for branch in method.findall('Branch') %} +{% if branches.append(branch) %}{% endif %} +{% endfor %} +{% endfor %} {# ExecutionOuts #} // ExecutionOuts begin {{ nodemacro.ExecutionOutDefinitions(Class, attribute_QualifiedName)}} +{% if not Class.attrib['ExtendConfigureSlots'] is defined %} size_t {{attribute_QualifiedName}}::GetRequiredOutCount() const { return {{Class.findall('Output')|length + branches|length}}; }{% endif %} // ExecutionOuts end {# Reflect #} + +{% if Class.attrib['ExtendReflectionSerialize'] is defined %} +{% set ExtendReflectionSerialize = "defined" %} +{% set preSerialize = "serializeBuilder" %} +{% set postSerialize = ";" %} +{% else %} +{% set preSerialize = "" %} +{% set postSerialize = "" %} +{% endif %} + +{% if Class.attrib['ExtendReflectionEdit'] is defined %} +{% set ExtendReflectionEdit = "defined" %} +{% set preEdit = "editorBuilder" %} +{% set postEdit = ";" %} +{% else %} +{% set preEdit = "" %} +{% set postEdit = "" %} +{% endif %} + +{% if Class.attrib['ExtendReflectionBehavior'] is defined %} +{% set ExtendReflectionBehavior = "defined" %} +{% set preBehavior = "behaviorBuilder" %} +{% set postBehavior = ";" %} +{% else %} +{% set preBehavior = "" %} +{% set postBehavior = "" %} +{% endif %} + void {{attribute_QualifiedName}}::Reflect(AZ::ReflectContext* context) { using namespace ScriptCanvas; if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { - serializeContext->Class<{{ attribute_Name }}{% if attribute_Base is defined %}, {{ attribute_Base }}{% endif %}>() +{% if ExtendReflectionSerialize is defined %} auto {{preSerialize}} = {% else %} {% endif %}serializeContext->Class<{{ attribute_Name }}{% if attribute_Base is defined %}, {{ attribute_Base }}{% endif %}>(){{postSerialize}} {% if attribute_EventHandler is defined %} - ->EventHandler<{{ attribute_EventHandler }}>() + {{preSerialize}}->EventHandler<{{ attribute_EventHandler }}>(){{postSerialize}} {% endif %} {# Serialized Properties #} {% for Property in Class.iter('Property') %} {% set property_Name = Property.attrib['Name'] %} - ->Field("{{ property_Name }}", &{{ attribute_Name }}::{{ property_Name | replace(' ','') }}) + {{preSerialize}}->Field("{{ property_Name }}", &{{ attribute_Name }}::{{ property_Name | replace(' ','') }}){{postSerialize}} {% endfor %} ; +{% if ExtendReflectionSerialize is defined %} + ExtendReflectionSerialize(&{{preSerialize}}); +{% endif %} + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { - editContext->Class<{{ attribute_QualifiedName }}>("{{ attribute_PreferredClassName }}", "{{ attribute_Description }}") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - +{% if ExtendReflectionEdit is defined %} auto {{preEdit}} = {% else %} {% endif %}editContext->Class<{{ attribute_QualifiedName }}>("{{ attribute_PreferredClassName }}", "{{ attribute_Description }}"){{postEdit}} + {{preEdit}}->ClassElement(AZ::Edit::ClassElements::EditorData, ""){{postEdit}} + {{preEdit}}->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly){{postEdit}} {% if attribute_Category is defined %} - ->Attribute(AZ::Edit::Attributes::Category, "{{ attribute_Category }}") + {{preEdit}}->Attribute(AZ::Edit::Attributes::Category, "{{ attribute_Category }}"){{postEdit}} {%- endif %} {% if attribute_Icon is defined %} - ->Attribute(AZ::Edit::Attributes::Icon, "{{ attribute_Icon }}") + {{preEdit}}->Attribute(AZ::Edit::Attributes::Icon, "{{ attribute_Icon }}"){{postEdit}} {%- endif %} {% if attribute_Deprecated is defined %} - ->Attribute(AZ::Edit::Attributes::Deprecated, "{{ attribute_Deprecated }}") + {{preEdit}}->Attribute(AZ::Edit::Attributes::Deprecated, "{{ attribute_Deprecated }}"){{postEdit}} {%- endif %} {% set uihandler = 'AZ::Edit::UIHandlers::Default' %} {% for item in Class.iter('Property') %} @@ -203,29 +201,34 @@ void {{attribute_QualifiedName}}::Reflect(AZ::ReflectContext* context) {% if item.attrib['Description'] is defined %} {% set description = item.attrib['Description'] %} {% endif %} - // {{ item.attrib['Name'] }} - ->DataElement({{ uihandler }}, &{{ attribute_Name }}::{{ item.attrib['Name'] }}, "{{ item.attrib['Name'] }}", "{{ description }}") + // {{ item.attrib['Name'] }} + {{preEdit}}->DataElement({{ uihandler }}, &{{ attribute_Name }}::{{ item.attrib['Name'] }}, "{{ item.attrib['Name'] }}", "{{ description }}"){{postEdit}} {% for EditAttribute in item.iter('EditAttribute') %} - ->Attribute({{ EditAttribute.attrib['Key'] }}, {{ EditAttribute.attrib['Value'] }}) + {{preEdit}}->Attribute({{ EditAttribute.attrib['Key'] }}, {{ EditAttribute.attrib['Value'] }}){{postEdit}} {% endfor %} {% endfor %} ; +{% if ExtendReflectionEdit is defined %} + ExtendReflectionEdit(&{{preEdit}}); +{% endif %} } } // Behavior Context Reflection if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class<{{ attribute_Name }}>("{{ attribute_Name }}") - ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List) - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) +{% if ExtendReflectionBehavior is defined %} auto {{preBehavior}} = {% else %} {% endif %}behaviorContext->Class<{{ attribute_Name }}>("{{ attribute_Name }}"){{postBehavior}} + {{preBehavior}}->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List){{postBehavior}} + {{preBehavior}}->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common){{postBehavior}} {% for inputMethod in Class.iter('Input') %} {% set methodName = inputMethod.attrib['Name'] %} // {{ inputMethod.attrib['Name'] }} - ->Method(Grammar::ToIdentifier("{{ macros.SlotName(methodName) }}").c_str(), &{{ attribute_Name }}::{{ macros.CleanName(methodName) }}) + {{preBehavior}}->Method(Grammar::ToIdentifier("{{ macros.SlotName(methodName) }}").c_str(), &{{ attribute_Name }}::{{ macros.CleanName(methodName) }}){{postBehavior}} {% endfor %} - ; +{% if ExtendReflectionBehavior is defined %} + ExtendReflectionBehavior(&{{preBehavior}}); +{% endif %} } } @@ -253,27 +256,32 @@ Nodes::{{ nodeableNodeName }}::{{ nodeableNodeName }}() {# NodeableNode Reflection #} void Nodes::{{ nodeableNodeName }}::Reflect(AZ::ReflectContext* context) { - {{ attribute_QualifiedName }}::Reflect(context); // Serialization Context Reflection if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { - serializeContext->Class<{{ nodeableNodeName }}, NodeableNode>() + {%if ExtendReflectionSerialize is defined%}auto {{preSerialize}} = {%endif%}serializeContext->Class<{{ nodeableNodeName }}, NodeableNode>(){{postSerialize}} {% if attribute_Version is defined %} - ->Version({{ attribute_Version }}{% if attribute_VersionConverter is defined %}, &{{ attribute_VersionConverter }}{% endif %}) + {{preSerialize}}->Version({{ attribute_Version }}{% if attribute_VersionConverter is defined %}, &{{ attribute_VersionConverter }}{% endif %}){{postSerialize}} {% else %} - ->Version(0) + {{preSerialize}}->Version(0){{postSerialize}} +{% endif %} + ; +{% if ExtendReflectionSerialize is defined %} + ExtendReflectionSerialize(&{{preSerialize}}); {% endif %} - ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { - editContext->Class<{{ nodeableNodeName }}>("{{ attribute_PreferredClassName }}", "{{ attribute_Description }}") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ; + {% if ExtendReflectionEdit is defined %}auto {{preEdit}} = {%endif%}editContext->Class<{{ nodeableNodeName }}>("{{ attribute_PreferredClassName }}", "{{ attribute_Description }}"){{postEdit}} + {{preEdit}}->ClassElement(AZ::Edit::ClassElements::EditorData, ""){{postEdit}} + {{preEdit}}->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly){{postEdit}} + {{preEdit}}->Attribute(AZ::Edit::Attributes::AutoExpand, true){{postEdit}} + ; +{% if ExtendReflectionEdit is defined %} + ExtendReflectionEdit(&{{preEdit}}); +{% endif %} } } } @@ -324,6 +332,7 @@ void Nodes::{{ nodeableNodeName }}::ConfigureVisualExtensions() RegisterExtension(visualExtensions); } {% endfor %} + OnConfigureVisualExtensions(); } {# ConfigureSlots #} @@ -457,6 +466,9 @@ void Nodes::{{ nodeableNodeName }}::ConfigureSlots() {% endfor %} #} +{% if Class.attrib['ExtendConfigureSlots'] is defined %} + ExtendConfigureSlots(ins, outs); +{% endif %} // Generate the execution map m_slotExecutionMap = SlotExecution::Map(AZStd::move(ins), AZStd::move(outs)); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvas_Nodeable_Macros.jinja b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvas_Nodeable_Macros.jinja index addd24f5d3..a7300791e8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvas_Nodeable_Macros.jinja +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/AutoGen/ScriptCanvas_Nodeable_Macros.jinja @@ -349,7 +349,4 @@ void {{qualifiedName}}::Call{{CleanName(outName)}}({{ExecutionOutReturnDefinitio {%- for executionOut in Class.findall('Output') -%} {{ ExecutionOutDefinition(Class, qualifiedName, executionOut, loop.index0 + branches|length) }} {%- endfor %} - -size_t {{qualifiedName}}::GetRequiredOutCount() const { return {{Class.findall('Output')|length + branches|length}}; } - -{% endmacro %} +{% endmacro %} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h index 5b1e5eee76..8f3cefa138 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Core.h @@ -250,7 +250,6 @@ namespace ScriptCanvas }; using ScriptCanvasSettingsRequestBus = AZ::EBus; - } namespace AZStd diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp index 30e55cee49..64c9f2497d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.cpp @@ -1476,9 +1476,11 @@ namespace ScriptCanvas const void* Datum::GetValueAddress() const { - return m_type.GetType() != Data::eType::BehaviorContextObject - ? AZStd::any_cast(&m_storage) - : (*AZStd::any_cast(&m_storage))->Get(); + return !m_storage.empty() + ? m_type.GetType() != Data::eType::BehaviorContextObject + ? AZStd::any_cast(&m_storage) + : (*AZStd::any_cast(&m_storage))->Get() + : nullptr; } bool Datum::Initialize(const Data::Type& type, eOriginality originality, const void* source, const AZ::Uuid& sourceTypeID) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h index 781dcb9ed8..be6f3ee37e 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Datum.h @@ -389,7 +389,7 @@ namespace ScriptCanvas bool Datum::Empty() const { - return GetValueAddress() == nullptr; + return m_storage.empty() || GetValueAddress() == nullptr; } template diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp index 4a936c8824..98d5e6b121 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp @@ -3577,12 +3577,12 @@ namespace ScriptCanvas } if (targetSlotType == CombinedSlotType::DataOut - && executionSlot.GetType() == CombinedSlotType::ExecutionIn - && executionInCount > 1) + && executionSlot.GetType() == CombinedSlotType::ExecutionIn + && executionInCount > 1) { if (!executionChildSlot || executionChildSlot->GetType() != CombinedSlotType::ExecutionOut) { - return AZ::Failure(AZStd::string("Data out by ExcutionIn must have child out slot")); + return AZ::Failure(AZStd::string("Data out by ExecutionIn must have child out slot")); } } @@ -3626,6 +3626,11 @@ namespace ScriptCanvas return {}; } + Grammar::MultipleFunctionCallFromSingleSlotInfo Node::GetMultipleFunctionCallFromSingleSlotInfo([[maybe_unused]] const Slot& slot) const + { + return {}; + } + VariableId Node::GetVariableIdRead(const Slot*) const { return {}; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h index a2d06686e9..42ffaec8da 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h @@ -715,6 +715,8 @@ namespace ScriptCanvas virtual PropertyFields GetPropertyFields() const; + virtual Grammar::MultipleFunctionCallFromSingleSlotInfo GetMultipleFunctionCallFromSingleSlotInfo(const Slot& slot) const; + virtual VariableId GetVariableIdRead(const Slot*) const; virtual VariableId GetVariableIdWritten(const Slot*) const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.h index 0193641d97..c1c9db6f8b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.h @@ -73,6 +73,8 @@ namespace ScriptCanvas void ConfigureSlots() override; + virtual void OnConfigureVisualExtensions() {} + AZ::Outcome GetBehaviorContextClass() const; ConstSlotsOutcome GetBehaviorContextOutName(const Slot& inSlot) const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h index 8426e90515..7b74f3dd81 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/PureData.h @@ -46,6 +46,8 @@ namespace ScriptCanvas const AZStd::unordered_map>& GetPropertyNameSlotMap() const; + AZ_INLINE AZ::Outcome GetDependencies() const override { return AZ::Success(DependencyReport{}); } + ~PureData() override; protected: diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 732455857e..db45f6bfe3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -2249,6 +2249,10 @@ namespace ScriptCanvas } #endif AddAllVariablesPreParse(); + if (!IsErrorFree()) + { + return; + } for (auto& nodeEntity : m_source.m_graphData->m_nodes) { @@ -2270,6 +2274,16 @@ namespace ScriptCanvas { AddError(nullptr, ValidationConstPtr(aznew NullEntityInGraph())); } + + if (!IsErrorFree()) + { + return; + } + } + + if (!IsErrorFree()) + { + return; } ParseAutoConnectedEBusHandlerVariables(); @@ -2638,7 +2652,8 @@ namespace ScriptCanvas AZStd::vector inputVariableIds; AZStd::unordered_map inputVariablesById; - for (auto variable : GetVariables()) + auto& variables = GetVariables(); + for (auto variable : variables) { auto constructionRequirement = ParseConstructionRequirement(variable); @@ -2655,18 +2670,30 @@ namespace ScriptCanvas case VariableConstructionRequirement::InputNodeable: { + if (variable->m_datum.Empty()) + { + AddError(nullptr, aznew Internal::ParseError(AZ::EntityId{}, "Empty nodeable datum in variable, probably due to a problem with azrtti declarations")); + break; + } + // I solemnly swear no harm shall come to the nodeable const Nodeable* nodeableSource = reinterpret_cast(variable->m_datum.GetAsDanger()); - AZ_Assert(nodeableSource != nullptr, "the must be a raw nodeable held by this pointer"); - AZ_Assert(azrtti_typeid(nodeableSource) != azrtti_typeid(), "type problem with nodeable"); + + if (!nodeableSource) + { + AddError(nullptr, aznew Internal::ParseError(AZ::EntityId{}, "No raw nodeable held by variable")); + break; + } + nodeablesById.push_back({ variable->m_nodeableNodeId, const_cast(nodeableSource) }); } break; case VariableConstructionRequirement::InputVariable: { - inputVariableIds.push_back(variable->m_sourceVariableId); - inputVariablesById.insert({ variable->m_sourceVariableId, variable }); + auto variableID = variable->m_sourceVariableId.IsValid() ? variable->m_sourceVariableId : VariableId::MakeVariableId(); + inputVariableIds.push_back(variableID); + inputVariablesById.insert({ variableID, variable }); // sort revealed a datum copy issue: type is not preserved, workaround below // m_runtimeInputs.m_variables.emplace_back(variable->m_sourceVariableId, variable->m_datum); } @@ -4310,6 +4337,7 @@ namespace ScriptCanvas { if (auto variable = FindVariable(execution->GetNodeId())) { + execution->MarkInputHasThisPointer(); execution->AddInput({ nullptr, variable, DebugDataSource::FromInternal() }); } else @@ -4327,6 +4355,7 @@ namespace ScriptCanvas { auto variable = AZStd::make_shared(); variable->m_datum = Datum(eventHandling->m_handlerName); + execution->MarkInputHasThisPointer(); execution->AddInput({ nullptr, variable, DebugDataSource::FromInternal() }); } else @@ -4338,6 +4367,7 @@ namespace ScriptCanvas { if (auto variable = FindVariable(execution->GetNodeId())) { + execution->MarkInputHasThisPointer(); execution->AddInput({ nullptr, variable, DebugDataSource::FromInternal() }); } else @@ -4367,12 +4397,159 @@ namespace ScriptCanvas void AbstractCodeModel::ParseMultiExecutionPost(ExecutionTreePtr execution) { ParsePropertyExtractionsPost(execution); + ParseMultipleFunctionCallPost(execution); } void AbstractCodeModel::ParseMultiExecutionPre(ExecutionTreePtr execution) { ParsePropertyExtractionsPre(execution); - } + } + + void AbstractCodeModel::ParseMultipleFunctionCallPost(ExecutionTreePtr execution) + { + auto& id = execution->GetId(); + MultipleFunctionCallFromSingleSlotInfo info = id.m_node->GetMultipleFunctionCallFromSingleSlotInfo(*id.m_slot); + + if (info.functionCalls.empty()) + { + return; + } + + auto parent = execution->ModParent(); + + if (!parent) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), "Null parent in MultipleFunctionCall")); + return; + } + + size_t indexInParentCall = parent->FindChildIndex(execution); + if (indexInParentCall >= parent->GetChildrenCount()) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotNoChildren)); + return; + } + + ExecutionChild* executionChildInParent = &parent->ModChild(indexInParentCall); + + const size_t executionInputCount = execution->GetInputCount(); + const size_t thisInputOffset = execution->InputHasThisPointer() ? 1 : 0; + + // the original index has ALL the input from the slots on the node + // create multiple calls with separate function call nodes, but ONLY take the inputs required + // as indicated by the function call info + + AZStd::unordered_set usedSlots; + bool variadicIsFound = false; + + auto createChild = [&](auto parentCall, ExecutionChild* childInParent, auto& functionCallInfo) + { + auto child = CreateChild(parentCall, id.m_node, id.m_slot); + child->SetSymbol(Symbol::FunctionCall); + child->SetName(functionCallInfo.functionName); + child->SetNameLexicalScope(functionCallInfo.lexicalScope); + childInParent->m_execution = child; + return child; + }; + + auto addThisInput = [&](auto functionCall) + { + if (thisInputOffset != 0) + { + if (executionInputCount == 0) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotNotEnoughInputForThis)); + return; + } + + const ExecutionInput& input = execution->GetInput(0); + usedSlots.insert(input.m_slot); + functionCall->AddInput(input); + } + }; + + auto addSlotInput = [&](auto functionCall, size_t inputIndex) + { + if (inputIndex >= executionInputCount) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotNotEnoughInput)); + return; + } + + const ExecutionInput& input = execution->GetInput(inputIndex); + + if (usedSlots.contains(input.m_slot)) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotNotEnoughInput)); + return; + } + + usedSlots.insert(input.m_slot); + + if (input.m_value->m_source == execution) + { + input.m_value->m_source = functionCall; + } + + functionCall->AddInput(input); + }; + + auto addCall = [&](auto& functionCallInfo, auto childInParent, size_t startingIndex, size_t sentinel, size_t variadicOffset = 0) + { + auto child = createChild(parent, childInParent, functionCallInfo); + addThisInput(child); + + for (size_t index = startingIndex; index < sentinel; ++index) + { + const size_t inputIndex = index + thisInputOffset + variadicOffset; + addSlotInput(child, inputIndex); + } + + child->AddChild({}); + childInParent = &child->ModChild(0); + return AZStd::make_pair(childInParent, child); + }; + + // loop through each call... + for (auto& functionCallInfo : info.functionCalls) + { + // ...first add any pre-variadic calls, using the starting index and the number of args, since they could come in any order, not input slot order... + if (!functionCallInfo.isVariadic) + { + AZStd::pair childInParentAndParent = addCall(functionCallInfo, executionChildInParent, functionCallInfo.startingIndex, functionCallInfo.startingIndex + functionCallInfo.numArguments); + executionChildInParent = childInParentAndParent.first; + parent = childInParentAndParent.second; + } + else + { + // ...then add only one variadic call if there is one... + if (variadicIsFound) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotMultipleVariadic)); + return; + } + + variadicIsFound = true; + const size_t sentinel = executionInputCount == 0 ? 0 : executionInputCount - thisInputOffset; + // ... by looping through the remaining slots, striding by functionCallInfo.numArguments, making repeated calls to the function + for (size_t slotInputIndex = functionCallInfo.startingIndex; slotInputIndex < sentinel; slotInputIndex += functionCallInfo.numArguments) + { + AZStd::pair childInParentAndParent = addCall(functionCallInfo, executionChildInParent, 0, functionCallInfo.numArguments, slotInputIndex); + executionChildInParent = childInParentAndParent.first; + parent = childInParentAndParent.second; + } + } + } + + if (info.errorOnUnusedSlot && usedSlots.size() != executionInputCount) + { + AddError(execution, aznew Internal::ParseError(id.m_node->GetEntityId(), ParseErrors::MultipleFunctionCallFromSingleSlotUnused)); + } + + // parent now refers to the last child call created + parent->SwapChildren(execution); + execution->Clear(); + } void AbstractCodeModel::ParseNodelingVariables(const Node& node, NodelingType nodelingType) { @@ -5146,6 +5323,6 @@ namespace ScriptCanvas return type == Data::eType::BehaviorContextObject; } - } + } -} +} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h index f1ad7b986b..8b8be27fab 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h @@ -387,6 +387,8 @@ namespace ScriptCanvas void ParseMultiExecutionPre(ExecutionTreePtr execution); + void ParseMultipleFunctionCallPost(ExecutionTreePtr execution); + void ParseNodelingVariables(const Node& node, NodelingType nodelingType); void ParseOperatorArithmetic(ExecutionTreePtr execution); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp index e16a3bc815..131209a521 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ParsingUtilities.cpp @@ -1132,14 +1132,14 @@ namespace ScriptCanvas } else if (variable->m_isExposedToConstruction) { - if (variable->m_sourceVariableId.IsValid()) - { - return VariableConstructionRequirement::InputVariable; - } - else if (variable->m_nodeableNodeId.IsValid()) + if (variable->m_nodeableNodeId.IsValid()) { return VariableConstructionRequirement::InputNodeable; } + else if (variable->m_sourceVariableId.IsValid()) + { + return VariableConstructionRequirement::InputVariable; + } else { AZ_Assert(false, "A member variable in the model has no valid id"); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.h index ab047fb580..d7e4fa0f72 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/Primitives.h @@ -164,6 +164,34 @@ namespace ScriptCanvas virtual void PostParseExecutionTreeBody(AbstractCodeModel& /*model*/, ExecutionTreePtr /*execution*/) {} }; + // for now, no return values supported + struct MultipleFunctionCallFromSingleSlotEntry + { + AZ_TYPE_INFO(MultipleFunctionCallFromSingleSlotEntry, "{360A23A3-C490-4047-B71E-64E290E441D3}"); + AZ_CLASS_ALLOCATOR(MultipleFunctionCallFromSingleSlotEntry, AZ::SystemAllocator, 0); + + bool isVariadic = false; + AZStd::string functionName; + LexicalScope lexicalScope; + size_t numArguments = 0; // stride in case isVariadic == true + size_t startingIndex = 0; // the index of the slot order + }; + + // for now, no return values supported + struct MultipleFunctionCallFromSingleSlotInfo + { + AZ_TYPE_INFO(MultipleFunctionCallFromSingleSlotInfo, "{DF51F08A-8B28-4851-9888-9AB7CC0B90D2}"); + AZ_CLASS_ALLOCATOR(MultipleFunctionCallFromSingleSlotInfo, AZ::SystemAllocator, 0); + + // this could likely be implemented, but needs care to duplicate input that the execution-slot created + // bool errorOnReusedSlot = false; + + bool errorOnUnusedSlot = false; + + // calls are executed in the order they arrive in the vector + AZStd::vector functionCalls; + }; + struct NodeableParse : public AZStd::enable_shared_from_this { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp index ed61d7e838..66f609768d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp @@ -313,6 +313,11 @@ namespace ScriptCanvas return !m_returnValues.empty(); } + bool ExecutionTree::InputHasThisPointer() const + { + return m_inputHasThisPointer; + } + bool ExecutionTree::IsInfiniteLoopDetectionPoint() const { return m_isInfiniteLoopDetectionPoint; @@ -377,6 +382,11 @@ namespace ScriptCanvas m_isInfiniteLoopDetectionPoint = true; } + void ExecutionTree::MarkInputHasThisPointer() + { + m_inputHasThisPointer = true; + } + void ExecutionTree::MarkInputOutputPreprocessed() { m_isInputOutputPreprocessed = true; @@ -587,6 +597,32 @@ namespace ScriptCanvas m_symbol = val; } - } + void ExecutionTree::SwapChildren(ExecutionTreePtr execution) + { + if (execution) + { + m_children.swap(execution->m_children); + for (auto& child : m_children) + { + if (child.m_execution) + { + child.m_execution->SetParent(shared_from_this()); + } + } + + for (auto& orphan : execution->m_children) + { + if (orphan.m_execution) + { + orphan.m_execution->SetParent(execution); + } + } + } + else + { + ClearChildren(); + } + } + } } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h index 3d0d75b313..17b86c8da4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h @@ -190,6 +190,8 @@ namespace ScriptCanvas bool HasReturnValues() const; + bool InputHasThisPointer() const; + bool IsInfiniteLoopDetectionPoint() const; void InsertChild(size_t index, const ExecutionChild& child); @@ -208,6 +210,8 @@ namespace ScriptCanvas void MarkInfiniteLoopDetectionPoint(); + void MarkInputHasThisPointer(); + void MarkInputOutputPreprocessed(); void MarkInternalOut(); @@ -262,6 +266,8 @@ namespace ScriptCanvas void SetSymbol(Symbol val); + void SwapChildren(ExecutionTreePtr execution); + private: // the (possible) slot(s) through which execution exited, along with associated output AZStd::vector m_children; @@ -275,6 +281,8 @@ namespace ScriptCanvas bool m_isInfiniteLoopDetectionPoint = false; + bool m_inputHasThisPointer = false; + bool m_isInputOutputPreprocessed = false; bool m_isInternalOut = false; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h index def4fa7761..68c6a8442a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h @@ -57,6 +57,12 @@ namespace ScriptCanvas constexpr const char* MissingVariableForEBusHandlerAddress = "missing variable for ebus handler address"; constexpr const char* MissingVariableForEBusHandlerAddressConnected = "missing variable for ebus handler address"; constexpr const char* MultipleExecutionOutConnections = "This node has multiple, unordered execution Out connections"; + constexpr const char* MultipleFunctionCallFromSingleSlotMultipleVariadic = "Only one variadic call (the last one) is supported in the multi-call per single slot."; + constexpr const char* MultipleFunctionCallFromSingleSlotNoChildren = "Node missing from parent children."; + constexpr const char* MultipleFunctionCallFromSingleSlotNotEnoughInput = "Not enough input to support multi call input information."; + constexpr const char* MultipleFunctionCallFromSingleSlotNotEnoughInputForThis = "Node doesn't have enough input for a parsed this pointer."; + constexpr const char* MultipleFunctionCallFromSingleSlotReused = "Multiple function slot reused an input slot"; + constexpr const char* MultipleFunctionCallFromSingleSlotUnused = "Multiple function slot left an input slot unused."; constexpr const char* MultipleSimulaneousInputValues = "Multiple values routed to the same single input with no way to discern which to take."; constexpr const char* MultipleStartNodes = "Multiple Start nodes in a single graph. Only one is allowed."; constexpr const char* NoChildrenAfterRoot = "No children after parsing function root"; diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_RunAllTransformNodes.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_RunAllTransformNodes.scriptcanvas index 45b24bad8d..c3b3599325 100644 --- a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_RunAllTransformNodes.scriptcanvas +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_RunAllTransformNodes.scriptcanvas @@ -3,34 +3,34 @@ - + - + - + - + - + - + - + @@ -62,12 +62,13 @@ + - + @@ -99,12 +100,13 @@ + - + @@ -141,12 +143,13 @@ + - + @@ -178,6 +181,7 @@ + @@ -189,7 +193,7 @@ - + @@ -199,26 +203,26 @@ - + - + - + - + - + - + @@ -250,12 +254,13 @@ + - + @@ -287,12 +292,13 @@ + - + @@ -329,12 +335,646 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -371,12 +1011,13 @@ + - + @@ -408,6 +1049,7 @@ + @@ -419,7 +1061,7 @@ - + @@ -431,7 +1073,7 @@ - + @@ -441,26 +1083,26 @@ - + - + - + - + - + - + @@ -492,12 +1134,13 @@ + - + @@ -529,484 +1172,13 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1043,12 +1215,13 @@ + - + @@ -1080,21 +1253,10 @@ + - - - - - - - - - - - - @@ -1103,7 +1265,7 @@ - + @@ -1113,26 +1275,26 @@ - + - + - + - + - + - + @@ -1164,12 +1326,13 @@ + - + @@ -1201,200 +1364,13 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1431,12 +1407,56 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1446,10 +1466,10 @@ - + - + @@ -1468,6 +1488,7 @@ + @@ -1479,9 +1500,21 @@ - + - + + + + + + + + + + + + + @@ -1489,26 +1522,26 @@ - + - + - + - + - + - + @@ -1540,12 +1573,338 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1577,12 +1936,205 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1619,12 +2171,13 @@ + - + @@ -1639,7 +2192,7 @@ - + @@ -1661,12 +2214,13 @@ + - + @@ -1676,10 +2230,10 @@ - + - + @@ -1698,6 +2252,7 @@ + @@ -1709,19 +2264,19 @@ - + - + - + @@ -1731,26 +2286,26 @@ - + - + - + - + - + - + @@ -1782,12 +2337,13 @@ + - + @@ -1819,12 +2375,13 @@ + - + @@ -1839,7 +2396,7 @@ - + @@ -1861,12 +2418,56 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1898,6 +2499,7 @@ + @@ -1909,36 +2511,107 @@ - + + + + + + + + + + + + + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1970,12 +2643,13 @@ + - + @@ -2007,12 +2681,13 @@ + - + @@ -2049,12 +2724,205 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2091,12 +2959,13 @@ + - + @@ -2128,6 +2997,7 @@ + @@ -2139,7 +3009,7 @@ - + @@ -2151,7 +3021,7 @@ - + @@ -2161,26 +3031,26 @@ - + - + - + - + - + - + @@ -2212,12 +3082,13 @@ + - + @@ -2249,12 +3120,13 @@ + - + @@ -2291,12 +3163,56 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2328,6 +3244,7 @@ + @@ -2339,36 +3256,1196 @@ - + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -2405,12 +4482,13 @@ + - + @@ -2447,12 +4525,13 @@ + - + @@ -2484,12 +4563,13 @@ + - + @@ -2521,6 +4601,7 @@ + @@ -2565,1709 +4646,26 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + @@ -4299,12 +4697,13 @@ + - + @@ -4336,12 +4735,13 @@ + - + @@ -4378,12 +4778,13 @@ + - + @@ -4420,12 +4821,13 @@ + - + @@ -4457,6 +4859,7 @@ + @@ -4480,7 +4883,7 @@ - + @@ -4490,26 +4893,26 @@ - + - + - + - + - + - + @@ -4541,12 +4944,13 @@ + - + @@ -4578,12 +4982,13 @@ + - + @@ -4620,850 +5025,13 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -5495,194 +5063,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -5694,9 +5075,9 @@ - + - + @@ -5704,703 +5085,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + @@ -6410,28 +5123,28 @@ - + - + - + - + - + - + - + @@ -6441,28 +5154,28 @@ - + - + - + - + - + - + - + @@ -6472,28 +5185,28 @@ - + - + - + - + - + - + - + @@ -6503,28 +5216,28 @@ - + - + - + - + - + - + - + @@ -6534,28 +5247,28 @@ - + - + - + - + - + - + - + @@ -6565,28 +5278,28 @@ - + - + - + - + - + - + - + @@ -6596,28 +5309,28 @@ - + - + - + - + - + - + - + @@ -6627,28 +5340,28 @@ - + - + - + - + - + - + - + @@ -6658,28 +5371,28 @@ - + - + - + - + - + - + - + @@ -6689,28 +5402,28 @@ - + - + - + - + - + - + @@ -6720,28 +5433,28 @@ - + - + - + - + - + - + - + @@ -6751,28 +5464,307 @@ - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6788,7 +5780,7 @@ - + @@ -6796,7 +5788,7 @@ - + @@ -6804,7 +5796,7 @@ - + @@ -6822,15 +5814,15 @@ - - - + + + - - - + + + @@ -6838,7 +5830,7 @@ - + @@ -6846,7 +5838,7 @@ - + @@ -6863,46 +5855,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -6911,18 +5867,12 @@ - - - - - - - + @@ -6930,637 +5880,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7586,7 +5906,7 @@ - + @@ -7594,7 +5914,7 @@ - + @@ -7602,7 +5922,595 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7620,15 +6528,15 @@ - - - + + + - - - + + + @@ -7636,7 +6544,7 @@ - + @@ -7644,7 +6552,7 @@ - + @@ -7661,46 +6569,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7709,18 +6581,12 @@ - - - - - - - + @@ -7728,7 +6594,7 @@ - + @@ -7746,15 +6612,15 @@ - - - + + + - - - + + + @@ -7762,7 +6628,7 @@ - + @@ -7771,9 +6637,9 @@ - - - + + + @@ -7783,7 +6649,7 @@ - + @@ -7791,49 +6657,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7851,15 +6675,15 @@ - - - + + + - - - + + + @@ -7867,7 +6691,7 @@ - + @@ -7875,7 +6699,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7893,15 +6759,15 @@ - - - + + + - - - + + + @@ -7915,60 +6781,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -7980,7 +6798,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -7988,25 +6834,33 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -8014,7 +6868,7 @@ - + From dbeee91e7bc8d654e41fb420132036d94513a6b5 Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 15:14:19 -0500 Subject: [PATCH 077/153] SPEC-7008: Setting up LargeWorlds main tests to be skipped in Debug builds --- .../dyn_veg/test_DynamicSliceInstanceSpawner.py | 6 ++++++ .../largeworlds/dyn_veg/test_EmptyInstanceSpawner.py | 6 ++++++ .../landscape_canvas/test_GraphComponentSync.py | 11 +++++++++++ 3 files changed, 23 insertions(+) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py index ead1e8779c..9235b302b8 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py @@ -16,6 +16,7 @@ import logging # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole @@ -46,6 +47,11 @@ class TestDynamicSliceInstanceSpawner(object): @pytest.mark.parametrize("launcher_platform", ['windows_editor']) def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + # Ensure temp level does not already exist file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py index ca71cd2137..83263c614a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py @@ -16,6 +16,7 @@ import logging # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) @@ -40,6 +41,11 @@ class TestEmptyInstanceSpawner(object): @pytest.mark.SUITE_main @pytest.mark.dynveg_area def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py index 855764fa6f..943d0cb985 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py @@ -23,6 +23,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts') @@ -46,6 +47,11 @@ class TestGraphComponentSync(object): @pytest.mark.BAT @pytest.mark.SUITE_main def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, editor, level, launcher_platform): + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ @@ -122,6 +128,11 @@ class TestGraphComponentSync(object): """ Verifies a Gradient Mixer can be setup in Landscape Canvas and all references are property set. """ + + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + cfg_args = [level] expected_lines = [ From ed0fab894b6cad4d8e151c4c109bf69307b8a285 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Thu, 3 Jun 2021 13:30:28 -0700 Subject: [PATCH 078/153] Added DiffuseGlobalIllumination level component --- .../DiffuseGlobalIlluminationComponent.cpp | 44 +++++++++ .../DiffuseGlobalIlluminationComponent.h | 38 ++++++++ ...ffuseGlobalIlluminationComponentConfig.cpp | 32 +++++++ ...DiffuseGlobalIlluminationComponentConfig.h | 43 +++++++++ ...fuseGlobalIlluminationComponentConstants.h | 23 +++++ ...eGlobalIlluminationComponentController.cpp | 92 +++++++++++++++++++ ...useGlobalIlluminationComponentController.h | 55 +++++++++++ .../DiffuseProbeGridComponent.cpp | 2 +- .../DiffuseProbeGridComponent.h | 4 +- .../DiffuseProbeGridComponentConstants.h | 0 .../DiffuseProbeGridComponentController.cpp | 4 +- .../DiffuseProbeGridComponentController.h | 2 +- ...itorDiffuseGlobalIlluminationComponent.cpp | 82 +++++++++++++++++ ...EditorDiffuseGlobalIlluminationComponent.h | 40 ++++++++ .../EditorDiffuseProbeGridComponent.cpp | 2 +- .../EditorDiffuseProbeGridComponent.h | 4 +- .../CommonFeatures/Code/Source/Module.cpp | 8 +- ...egration_commonfeatures_editor_files.cmake | 6 +- ...omlyintegration_commonfeatures_files.cmake | 14 ++- 19 files changed, 478 insertions(+), 17 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConstants.h create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridComponent.cpp (96%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridComponent.h (90%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridComponentConstants.h (100%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridComponentController.cpp (99%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridComponentController.h (98%) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.h rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/EditorDiffuseProbeGridComponent.cpp (99%) rename Gems/AtomLyIntegration/CommonFeatures/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/EditorDiffuseProbeGridComponent.h (97%) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.cpp new file mode 100644 index 0000000000..b14bcf28b8 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.cpp @@ -0,0 +1,44 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +namespace AZ +{ + namespace Render + { + + DiffuseGlobalIlluminationComponent::DiffuseGlobalIlluminationComponent(const DiffuseGlobalIlluminationComponentConfig& config) + : BaseClass(config) + { + } + + void DiffuseGlobalIlluminationComponent::Reflect(AZ::ReflectContext* context) + { + BaseClass::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class(); + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("DiffuseGlobalIlluminationComponentTypeId", BehaviorConstant(Uuid(DiffuseGlobalIlluminationComponentTypeId))) + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common); + } + } + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.h new file mode 100644 index 0000000000..a54e5868cd --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.h @@ -0,0 +1,38 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class DiffuseGlobalIlluminationComponent final + : public AzFramework::Components::ComponentAdapter + { + public: + using BaseClass = AzFramework::Components::ComponentAdapter; + AZ_COMPONENT(AZ::Render::DiffuseGlobalIlluminationComponent, DiffuseGlobalIlluminationComponentTypeId , BaseClass); + + DiffuseGlobalIlluminationComponent() = default; + DiffuseGlobalIlluminationComponent(const DiffuseGlobalIlluminationComponentConfig& config); + + static void Reflect(AZ::ReflectContext* context); + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.cpp new file mode 100644 index 0000000000..406da9db2e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.cpp @@ -0,0 +1,32 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + void DiffuseGlobalIlluminationComponentConfig::Reflect(ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("QualityLevel", &DiffuseGlobalIlluminationComponentConfig::m_qualityLevel) + ; + } + } + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h new file mode 100644 index 0000000000..23296967a5 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h @@ -0,0 +1,43 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AZ +{ + namespace Render + { + enum class DiffuseGlobalIlluminationQualityLevel : uint32_t + { + Low, + Medium, + High, + + Count + }; + + class DiffuseGlobalIlluminationComponentConfig final + : public ComponentConfig + { + public: + AZ_RTTI(DiffuseGlobalIlluminationComponentConfig, "{0D0835D6-6094-4EF8-BEAC-5FF8A4E4C119}", ComponentConfig); + AZ_CLASS_ALLOCATOR(DiffuseGlobalIlluminationComponentConfig, SystemAllocator, 0); + + static void Reflect(ReflectContext* context); + + DiffuseGlobalIlluminationQualityLevel m_qualityLevel; + }; + } +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConstants.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConstants.h new file mode 100644 index 0000000000..e89aa65584 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConstants.h @@ -0,0 +1,23 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +namespace AZ +{ + namespace Render + { + static constexpr const char* const DiffuseGlobalIlluminationComponentTypeId = "{D51F8033-EF0D-4A13-BED3-5B193555B8D2}"; + static constexpr const char* const EditorDiffuseGlobalIlluminationComponentTypeId = "{169378DD-4052-4A60-BD63-90B02CFA69C1}"; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp new file mode 100644 index 0000000000..4c7f37bd4a --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp @@ -0,0 +1,92 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include + +//#include + +#include +//#include + +namespace AZ +{ + namespace Render + { + void DiffuseGlobalIlluminationComponentController::Reflect(ReflectContext* context) + { + DiffuseGlobalIlluminationComponentConfig::Reflect(context); + + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0) + ->Field("Configuration", &DiffuseGlobalIlluminationComponentController::m_configuration); + } + } + + void DiffuseGlobalIlluminationComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC("DiffuseGlobalIlluminationService", 0x11b9cbe1)); + } + + void DiffuseGlobalIlluminationComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC("DiffuseGlobalIlluminationService", 0x11b9cbe1)); + } + + void DiffuseGlobalIlluminationComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + AZ_UNUSED(required); + } + + DiffuseGlobalIlluminationComponentController::DiffuseGlobalIlluminationComponentController(const DiffuseGlobalIlluminationComponentConfig& config) + : m_configuration(config) + { + } + + void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId) + { + m_entityId = entityId; + } + + void DiffuseGlobalIlluminationComponentController::Deactivate() + { + //m_postProcessInterface = nullptr; + m_entityId.SetInvalid(); + } + + void DiffuseGlobalIlluminationComponentController::SetConfiguration(const DiffuseGlobalIlluminationComponentConfig& config) + { + m_configuration = config; + OnConfigChanged(); + } + + const DiffuseGlobalIlluminationComponentConfig& DiffuseGlobalIlluminationComponentController::GetConfiguration() const + { + return m_configuration; + } + + void DiffuseGlobalIlluminationComponentController::OnConfigChanged() + { + // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. + //const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + //DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor(); + //DisplayMapperConfigurationDescriptor desc; + //desc.m_operationType = m_configuration.m_displayMapperOperation; + //desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled; + //desc.m_ldrColorGradingLut = m_configuration.m_ldrColorGradingLut; + //desc.m_acesParameterOverrides = m_configuration.m_acesParameterOverrides; + //fp->RegisterDisplayMapperConfiguration(desc); + } + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h new file mode 100644 index 0000000000..8700e1ffb5 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +#include + +//#include +//#include + +namespace AZ +{ + namespace Render + { + class DiffuseGlobalIlluminationComponentController final + { + public: + friend class EditorDiffuseGlobalIlluminationComponent; + + AZ_TYPE_INFO(AZ::Render::DiffuseGlobalIlluminationComponentController, "{7DE7D2A0-2526-447C-A11F-C31EE1332C26}"); + static void Reflect(AZ::ReflectContext* context); + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + + DiffuseGlobalIlluminationComponentController() = default; + DiffuseGlobalIlluminationComponentController(const DiffuseGlobalIlluminationComponentConfig& config); + + void Activate(EntityId entityId); + void Deactivate(); + void SetConfiguration(const DiffuseGlobalIlluminationComponentConfig& config); + const DiffuseGlobalIlluminationComponentConfig& GetConfiguration() const; + + private: + AZ_DISABLE_COPY(DiffuseGlobalIlluminationComponentController); + + void OnConfigChanged(); + + DiffuseGlobalIlluminationComponentConfig m_configuration; + EntityId m_entityId; + }; + } +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.cpp similarity index 96% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.cpp index 509cbb86e6..b042f594c6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.cpp @@ -10,7 +10,7 @@ * */ -#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.h similarity index 90% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.h index 964ce157bd..b77dceefac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.h @@ -12,8 +12,8 @@ #pragma once -#include -#include +#include +#include #include namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentConstants.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h similarity index 100% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentConstants.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp similarity index 99% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp index 5fb835de15..f5ac36e7f6 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp @@ -10,8 +10,8 @@ * */ -#include -#include +#include +#include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h similarity index 98% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h index 4122a07ba2..ef606d2170 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.cpp new file mode 100644 index 0000000000..bdb5686e89 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.cpp @@ -0,0 +1,82 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +//#include "Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h" + +#include +#include + +namespace AZ +{ + namespace Render + { + void EditorDiffuseGlobalIlluminationComponent::Reflect(AZ::ReflectContext* context) + { + BaseClass::Reflect(context); + + if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1); + + if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + { + editContext->Class( + "Diffuse Global Illumination", "Diffuse Global Illumination configuration") + ->ClassElement(Edit::ClassElements::EditorData, "") + ->Attribute(Edit::Attributes::Category, "Atom") + ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg") + ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Component_Placeholder.png") + ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector({ AZ_CRC("Level", 0x9aeacc13), AZ_CRC("Game", 0x232b318c) })) + ->Attribute(Edit::Attributes::AutoExpand, true) + ->Attribute(Edit::Attributes::HelpPageURL, "https://") + ; + + editContext->Class( + "ToneMapperComponentControl", "") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(AZ::Edit::UIHandlers::Default, &DiffuseGlobalIlluminationComponentController::m_configuration, "Configuration", "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ; + + editContext->Class("DiffuseGlobalIlluminationComponentConfig", "") + ->ClassElement(Edit::ClassElements::EditorData, "") + ->DataElement(Edit::UIHandlers::ComboBox, &DiffuseGlobalIlluminationComponentConfig::m_qualityLevel, "Quality Level", "Quality Level") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->EnumAttribute(DiffuseGlobalIlluminationQualityLevel::Low, "Low") + ->EnumAttribute(DiffuseGlobalIlluminationQualityLevel::Medium, "Medium") + ->EnumAttribute(DiffuseGlobalIlluminationQualityLevel::High, "High") + ; + } + } + + if (auto behaviorContext = azrtti_cast(context)) + { + behaviorContext->ConstantProperty("EditorDiffuseGlobalIlluminationComponentTypeId", BehaviorConstant(Uuid(EditorDiffuseGlobalIlluminationComponentTypeId))) + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation); + } + } + + EditorDiffuseGlobalIlluminationComponent::EditorDiffuseGlobalIlluminationComponent(const DiffuseGlobalIlluminationComponentConfig& config) + : BaseClass(config) + { + } + + u32 EditorDiffuseGlobalIlluminationComponent::OnConfigurationChanged() + { + m_controller.OnConfigChanged(); + return Edit::PropertyRefreshLevels::AttributesAndValues; + } + } +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.h new file mode 100644 index 0000000000..2a478665c5 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.h @@ -0,0 +1,40 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AZ +{ + namespace Render + { + class EditorDiffuseGlobalIlluminationComponent final + : public AzToolsFramework::Components::EditorComponentAdapter + { + public: + + using BaseClass = AzToolsFramework::Components::EditorComponentAdapter; + AZ_EDITOR_COMPONENT(AZ::Render::EditorDiffuseGlobalIlluminationComponent, EditorDiffuseGlobalIlluminationComponentTypeId, BaseClass); + + static void Reflect(AZ::ReflectContext* context); + + EditorDiffuseGlobalIlluminationComponent() = default; + EditorDiffuseGlobalIlluminationComponent(const DiffuseGlobalIlluminationComponentConfig& config); + + //! EditorRenderComponentAdapter overrides... + AZ::u32 OnConfigurationChanged() override; + }; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp similarity index 99% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 1e5b959803..caf9ecd007 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h similarity index 97% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h index 15c46d45ba..2e013ca479 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp index 2ef4e1e229..df8552e5c9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Module.cpp @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -47,7 +48,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -111,6 +113,7 @@ namespace AZ EntityReferenceComponent::CreateDescriptor(), GradientWeightModifierComponent::CreateDescriptor(), DiffuseProbeGridComponent::CreateDescriptor(), + DiffuseGlobalIlluminationComponent::CreateDescriptor(), DeferredFogComponent::CreateDescriptor(), SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(), AttachmentComponent::CreateDescriptor(), @@ -142,6 +145,7 @@ namespace AZ EditorEntityReferenceComponent::CreateDescriptor(), EditorGradientWeightModifierComponent::CreateDescriptor(), EditorDiffuseProbeGridComponent::CreateDescriptor(), + EditorDiffuseGlobalIlluminationComponent::CreateDescriptor(), EditorDeferredFogComponent::CreateDescriptor(), SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(), EditorAttachmentComponent::CreateDescriptor(), diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index e58f72a121..a68c54e85f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -23,8 +23,10 @@ set(FILES Source/CoreLights/EditorDirectionalLightComponent.cpp Source/Decals/EditorDecalComponent.h Source/Decals/EditorDecalComponent.cpp - Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.h - Source/DiffuseProbeGrid/EditorDiffuseProbeGridComponent.cpp + Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h + Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp + Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.h + Source/DiffuseGlobalIllumination/EditorDiffuseGlobalIlluminationComponent.cpp Source/Grid/EditorGridComponent.h Source/Grid/EditorGridComponent.cpp Source/ImageBasedLights/EditorImageBasedLightComponent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake index e13d1d37d6..7745306785 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_files.cmake @@ -43,10 +43,16 @@ set(FILES Source/Decals/DecalComponent.cpp Source/Decals/DecalComponentController.h Source/Decals/DecalComponentController.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridComponent.h - Source/DiffuseProbeGrid/DiffuseProbeGridComponent.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.h - Source/DiffuseProbeGrid/DiffuseProbeGridComponentController.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridComponent.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.h + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponent.cpp + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.cpp Source/Grid/GridComponent.h Source/Grid/GridComponent.cpp Source/Grid/GridComponentConfig.cpp From d90a3d46a7ac393a12807fe66eacd4f9bab7c8f1 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Thu, 3 Jun 2021 15:59:45 -0500 Subject: [PATCH 079/153] Support for nested slice conversions (#1121) This set of changes enables conversions for singly-nested slices. Multiple nesting hierarchies are only partially supported at this point. Conversion is also significantly more deterministic, which makes it easier to convert single slices without needing to reconvert every slice or level that relies on it as well. Changes: - Added version of Instance::AddInstance() that takes in an alias to allow for deterministic aliases - Added a "SliceConverterEditorEntityContextComponent" that's used to specifically disable entity activation on creation. The disabling is done this way vs adding a new public API, because the disable shouldn't be required in any normal case outside of this tool. - Disabled more AWS gems for the SliceConverter, as they're unneeded and cause issues if they're around in the tool. - Added a small null check to the Camera Controller. - Added the actual support for slice instance conversion. This instantiates the entities, applies the data patches, turns them into a prefab instance, and generates a JSON patch out of the changes. --- .../AzCore/AzCore/Slice/SliceComponent.h | 7 +- .../Prefab/Instance/Instance.cpp | 13 +- .../Prefab/Instance/Instance.h | 1 + .../SerializeContextTools/Application.cpp | 19 +- .../SerializeContextTools/SliceConverter.cpp | 230 +++++++++++++++--- .../SerializeContextTools/SliceConverter.h | 31 ++- ...iceConverterEditorEntityContextComponent.h | 65 +++++ Code/Tools/SerializeContextTools/main.cpp | 3 +- .../serializecontexttools_files.cmake | 1 + .../Code/Source/CameraComponentController.cpp | 5 +- .../gem_autoload.serializecontexttools.setreg | 6 + 11 files changed, 330 insertions(+), 51 deletions(-) create mode 100644 Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h diff --git a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.h b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.h index 5ef8df0617..0c9bad6d4a 100644 --- a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.h +++ b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.h @@ -971,6 +971,10 @@ namespace AZ */ void RestoreCachedInstances(); + /// Returns data flags for use when instantiating an instance of this slice. + /// These data flags include those harvested from the entire slice ancestry. + const DataFlagsPerEntity& GetDataFlagsForInstances() const; + protected: ////////////////////////////////////////////////////////////////////////// @@ -1004,9 +1008,6 @@ namespace AZ DataFlagsPerEntity* GetCorrectBundleOfDataFlags(EntityId entityId); const DataFlagsPerEntity* GetCorrectBundleOfDataFlags(EntityId entityId) const; - /// Returns data flags for use when instantiating an instance of this slice. - /// These data flags include those harvested from the entire slice ancestry. - const DataFlagsPerEntity& GetDataFlagsForInstances() const; void BuildDataFlagsForInstances(); /** diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 8f483ec818..766a293b4a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -49,8 +50,7 @@ namespace AzToolsFramework m_alias = GenerateInstanceAlias(); m_containerEntity = containerEntity ? AZStd::move(containerEntity) : AZStd::make_unique(); - EntityAlias containerEntityAlias = GenerateEntityAlias(); - RegisterEntity(m_containerEntity->GetId(), containerEntityAlias); + RegisterEntity(m_containerEntity->GetId(), PrefabDomUtils::ContainerEntityName); } Instance::~Instance() @@ -311,8 +311,15 @@ namespace AzToolsFramework Instance& Instance::AddInstance(AZStd::unique_ptr instance) { InstanceAlias newInstanceAlias = GenerateInstanceAlias(); + return AddInstance(AZStd::move(instance), newInstanceAlias); + } + + Instance& Instance::AddInstance(AZStd::unique_ptr instance, InstanceAlias newInstanceAlias) + { AZ_Assert(instance.get(), "instance argument is nullptr"); - AZ_Assert(m_nestedInstances.find(newInstanceAlias) == m_nestedInstances.end(), "InstanceAlias' unique id collision, this should never happen."); + AZ_Assert( + m_nestedInstances.find(newInstanceAlias) == m_nestedInstances.end(), + "InstanceAlias' unique id collision, this should never happen."); instance->m_parent = this; instance->m_alias = newInstanceAlias; return *(m_nestedInstances[newInstanceAlias] = std::move(instance)); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 68bc395012..4a69ade6d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -93,6 +93,7 @@ namespace AzToolsFramework void Reset(); Instance& AddInstance(AZStd::unique_ptr instance); + Instance& AddInstance(AZStd::unique_ptr instance, InstanceAlias instanceAlias); AZStd::unique_ptr DetachNestedInstance(const InstanceAlias& instanceAlias); /** diff --git a/Code/Tools/SerializeContextTools/Application.cpp b/Code/Tools/SerializeContextTools/Application.cpp index 81cc314deb..918afd731c 100644 --- a/Code/Tools/SerializeContextTools/Application.cpp +++ b/Code/Tools/SerializeContextTools/Application.cpp @@ -17,6 +17,7 @@ #include #include +#include namespace AZ { @@ -34,6 +35,9 @@ namespace AZ Application::Application(int argc, char** argv) : AzToolsFramework::ToolsApplication(&argc, &argv) { + // We need a specialized variant of EditorEntityContextCompnent for the SliceConverter, so we register the descriptor here. + RegisterComponentDescriptor(AzToolsFramework::SliceConverterEditorEntityContextComponent::CreateDescriptor()); + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); if (projectPath.empty()) { @@ -110,10 +114,21 @@ namespace AZ AZ::ComponentTypeList Application::GetRequiredSystemComponents() const { - // Use all of the default system components, but also add in the ThumbnailerNullComponent so that components requiring - // a ThumbnailService can still be started up. + // By default, we use all of the standard system components. AZ::ComponentTypeList components = AzToolsFramework::ToolsApplication::GetRequiredSystemComponents(); + + // Also add in the ThumbnailerNullComponent so that components requiring a ThumbnailService can still be started up. components.emplace_back(azrtti_typeid()); + + // The Slice Converter requires a specialized variant of the EditorEntityContextComponent that exposes the ability + // to disable the behavior of activating entities on creation. During conversion, the creation flow will be triggered, + // but entity activation requires a significant amount of subsystem initialization that's unneeded for conversion. + // So, to get around this, we swap out EditorEntityContextComponent with SliceConverterEditorEntityContextComponent. + components.erase( + AZStd::remove( + components.begin(), components.end(), azrtti_typeid()), + components.end()); + components.emplace_back(azrtti_typeid()); return components; } } // namespace SerializeContextTools diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index d06534e303..56b3689d6b 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -30,13 +30,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include + // SliceConverter reads in a slice file (saved in an ObjectStream format), instantiates it, creates a prefab out of the data, // and saves the prefab in a JSON format. This can be used for one-time migrations of slices or slice-based levels to prefabs. // @@ -99,12 +102,26 @@ namespace AZ bool result = true; rapidjson::StringBuffer scratchBuffer; + // For slice conversion, disable the EditorEntityContextComponent logic that activates entities on creation. + // This prevents a lot of error messages and crashes during conversion due to lack of full environment and subsystem setup. + AzToolsFramework::SliceConverterEditorEntityContextComponent::DisableOnContextEntityLogic(); + // Loop through the list of requested files and convert them. AZStd::vector fileList = Utilities::ReadFileListFromCommandLine(application, "files"); for (AZStd::string& filePath : fileList) { bool convertResult = ConvertSliceFile(convertSettings.m_serializeContext, filePath, isDryRun); result = result && convertResult; + + // Clear out all registered prefab templates between each top-level file that gets processed. + auto prefabSystemComponentInterface = AZ::Interface::Get(); + for (auto templateId : m_createdTemplateIds) + { + // We don't just want to call RemoveAllTemplates() because the root template should remain between file conversions. + prefabSystemComponentInterface->RemoveTemplate(templateId); + } + m_aliasIdMapper.clear(); + m_createdTemplateIds.clear(); } DisconnectFromAssetProcessor(); @@ -114,6 +131,13 @@ namespace AZ bool SliceConverter::ConvertSliceFile( AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun) { + /* To convert a slice file, we read the input file in via ObjectStream, then use the "class ready" callback to convert + * the data in memory to a Prefab. + * If the input file is a level file (.ly), we actually need to load the level slice file ("levelentities.editor_xml") from + * within the level file, which effectively is a zip file of the level slice file and a bunch of legacy level files that won't + * be converted, since the systems that would use them no longer exist. + */ + bool result = true; bool packOpened = false; @@ -144,7 +168,7 @@ namespace AZ AZ_STRING_ARG(fileExtension.Native())); } - auto callback = [&outputPath, isDryRun](void* classPtr, const Uuid& classId, SerializeContext* context) + auto callback = [this, &outputPath, isDryRun](void* classPtr, const Uuid& classId, SerializeContext* context) { if (classId != azrtti_typeid()) { @@ -178,6 +202,13 @@ namespace AZ bool SliceConverter::ConvertSliceToPrefab( AZ::SerializeContext* serializeContext, AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity) { + /* Given a root slice entity, we convert it to a prefab by doing the following: + * - Locate the SliceComponent + * - Take all the entities directly located on the slice, and put them into a prefab + * - Fix up any top-level entities to have the prefab container entity as their parent + * - If there are any nested slice instances, convert the nested slices to prefabs, then convert the instances. + */ + auto prefabSystemComponentInterface = AZ::Interface::Get(); // Find the slice from the root entity. @@ -192,9 +223,14 @@ namespace AZ SliceComponent::EntityList sliceEntities = sliceComponent->GetNewEntities(); AZ_Printf("Convert-Slice", " Slice contains %zu entities.\n", sliceEntities.size()); - // Create the Prefab with the entities from the slice + // Create the Prefab with the entities from the slice. + // The entities are added in a separate step so that we can give them deterministic entity aliases that match their entity Ids AZStd::unique_ptr sourceInstance( - prefabSystemComponentInterface->CreatePrefab(sliceEntities, {}, outputPath)); + prefabSystemComponentInterface->CreatePrefab({}, {}, outputPath)); + for (auto& entity : sliceEntities) + { + sourceInstance->AddEntity(*entity, AZStd::string::format("Entity_%s", entity->GetId().ToString().c_str())); + } // Dispatch events here, because prefab creation might trigger asset loads in rare circumstances. AZ::Data::AssetManager::Instance().DispatchEvents(); @@ -204,12 +240,28 @@ namespace AZ AzToolsFramework::Prefab::EntityOptionalReference container = sourceInstance->GetContainerEntity(); FixPrefabEntities(container->get(), sliceEntities); + // Keep track of the template Id we created, we're going to remove it at the end of slice file conversion to make sure + // the data doesn't stick around between file conversions. auto templateId = sourceInstance->GetTemplateId(); if (templateId == AzToolsFramework::Prefab::InvalidTemplateId) { AZ_Printf("Convert-Slice", " Path error. Path could be invalid, or the prefab may not be loaded in this level.\n"); return false; } + m_createdTemplateIds.emplace(templateId); + + // Save off a mapping of the original slice entity IDs to the new prefab template entity aliases. + // When converting nested slices, this mapping will be needed to fix up the parent entity hierarchy correctly. + auto entityAliases = sourceInstance->GetEntityAliases(); + for (auto& alias : entityAliases) + { + auto id = sourceInstance->GetEntityId(alias); + auto result = m_aliasIdMapper.emplace(TemplateEntityIdPair(templateId, id), alias); + if (!result.second) + { + AZ_Printf("Convert-Slice", " Duplicate entity alias -> entity id entries found, conversion may not be successful.\n"); + } + } // Update the prefab template with the fixed-up data in our prefab instance. AzToolsFramework::Prefab::PrefabDom prefabDom; @@ -254,21 +306,26 @@ namespace AZ // via an EditorRequests EBus in CreatePrefab, but the subsystem that listens for it isn't present in this tool.) AzToolsFramework::EditorEntityContextRequestBus::Broadcast( &AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, containerEntity); - containerEntity.AddComponent(aznew AzToolsFramework::Prefab::EditorPrefabComponent()); + if (containerEntity.FindComponent() == nullptr) + { + containerEntity.AddComponent(aznew AzToolsFramework::Prefab::EditorPrefabComponent()); + } + + // Make all the components on the container entity have deterministic component IDs, so that multiple runs of the tool + // on the same slice will produce the same prefab output. We're going to cheat a bit and just use the component type hash + // as the component ID. This would break if we had multiple components of the same type, but that currently doesn't + // happen for the container entity. + auto containerComponents = containerEntity.GetComponents(); + for (auto& component : containerComponents) + { + component->SetId(component->GetUnderlyingComponentType().GetHash()); + } // Reparent any root-level slice entities to the container entity. for (auto entity : sliceEntities) { - AzToolsFramework::Components::TransformComponent* transformComponent = - entity->FindComponent(); - if (transformComponent) - { - if (!transformComponent->GetParentId().IsValid()) - { - transformComponent->SetParent(containerEntity.GetId()); - transformComponent->UpdateCachedWorldTransform(); - } - } + constexpr bool onlySetIfInvalid = true; + SetParentEntity(*entity, containerEntity.GetId(), onlySetIfInvalid); } } @@ -276,9 +333,13 @@ namespace AZ SliceComponent* sliceComponent, AzToolsFramework::Prefab::Instance* sourceInstance, AZ::SerializeContext* serializeContext, bool isDryRun) { + /* Given a root slice, find all the nested slices and convert them. */ + + // Get the list of nested slices that this slice uses. const SliceComponent::SliceList& sliceList = sliceComponent->GetSlices(); auto prefabSystemComponentInterface = AZ::Interface::Get(); + // For each nested slice, convert it. for (auto& slice : sliceList) { // Get the nested slice asset @@ -312,7 +373,7 @@ namespace AZ return false; } - // Load the prefab template for the newly-created nested prefab. + // Find the prefab template we created for the newly-created nested prefab. // To get the template, we need to take our absolute slice path and turn it into a project-relative prefab path. AZ::IO::Path nestedPrefabPath = assetPath; nestedPrefabPath.ReplaceExtension("prefab"); @@ -346,11 +407,25 @@ namespace AZ } bool SliceConverter::ConvertSliceInstance( - [[maybe_unused]] AZ::SliceComponent::SliceInstance& instance, - [[maybe_unused]] AZ::Data::Asset& sliceAsset, + AZ::SliceComponent::SliceInstance& instance, + AZ::Data::Asset& sliceAsset, AzToolsFramework::Prefab::TemplateReference nestedTemplate, AzToolsFramework::Prefab::Instance* topLevelInstance) { + /* To convert a slice instance, it's important to understand the similarities and differences between slices and prefabs. + * Both slices and prefabs have the concept of instances of a nested slice/prefab, where each instance can have its own + * set of changed data (transforms, component values, etc). + * For slices, the changed data comes from applying a DataPatch to an instantiated set of entities from the nested slice. + * From prefabs, the changed data comes from Json patches that are applied to the instantiated set of entities from the + * nested prefab. The prefab instance entities also have different IDs than the slice instance entities, so we'll need + * to remap some of them along the way. + * To get from one to the other, we'll need to do the following: + * - Instantiate the nested slice and nested prefab + * - Patch the nested slice instance and fix up the entity ID references + * - Replace the nested prefab instance entities with the fixed-up slice ones + * - Add the nested instance (and the link patch) to the top-level prefab + */ + auto instanceToTemplateInterface = AZ::Interface::Get(); auto prefabSystemComponentInterface = AZ::Interface::Get(); @@ -371,22 +446,83 @@ namespace AZ AzToolsFramework::Prefab::PrefabDom unmodifiedNestedInstanceDom; instanceToTemplateInterface->GenerateDomForInstance(unmodifiedNestedInstanceDom, *(nestedInstance.get())); - // Currently, DataPatch conversions for nested slices aren't implemented, so all nested slice overrides will - // be lost. - AZ_Warning( - "Convert-Slice", false, " Nested slice instances will lose all of their override data during conversion.", - nestedTemplate->get().GetFilePath().c_str()); + // Instantiate a new instance of the nested slice + SliceComponent* dependentSlice = sliceAsset.Get()->GetComponent(); + [[maybe_unused]] AZ::SliceComponent::InstantiateResult instantiationResult = dependentSlice->Instantiate(); + AZ_Assert(instantiationResult == AZ::SliceComponent::InstantiateResult::Success, "Failed to instantiate instance"); - // Set the container entity of the nested prefab to have the top-level prefab as the parent. - // Once DataPatch conversions are supported, this will need to change to nest the prefab under the appropriate entity - // within the level. + // Apply the data patch for this instance of the nested slice. This will provide us with a version of the slice's entities + // with all data overrides applied to them. + DataPatch::FlagsMap sourceDataFlags = dependentSlice->GetDataFlagsForInstances().GetDataFlagsForPatching(); + DataPatch::FlagsMap targetDataFlags = instance.GetDataFlags().GetDataFlagsForPatching(&instance.GetEntityIdToBaseMap()); + AZ::ObjectStream::FilterDescriptor filterDesc(AZ::Data::AssetFilterNoAssetLoading); + + AZ::SliceComponent::InstantiatedContainer sourceObjects(false); + dependentSlice->GetEntities(sourceObjects.m_entities); + dependentSlice->GetAllMetadataEntities(sourceObjects.m_metadataEntities); + + const DataPatch& dataPatch = instance.GetDataPatch(); + auto instantiated = + dataPatch.Apply(&sourceObjects, dependentSlice->GetSerializeContext(), filterDesc, sourceDataFlags, targetDataFlags); + + // Run through all the instantiated entities and fix up their parent hierarchy: + // - Invalid parents need to get set to the container. + // - Valid parents into the top-level instance mean that the nested slice instance is also child-nested under an entity. + // Prefabs handle this type of nesting differently - we need to set the parent to the container, and the container's + // parent to that other instance. auto containerEntity = nestedInstance->GetContainerEntity(); - AzToolsFramework::Components::TransformComponent* transformComponent = - containerEntity->get().FindComponent(); - if (transformComponent) + auto containerEntityId = containerEntity->get().GetId(); + for (auto entity : instantiated->m_entities) { - transformComponent->SetParent(topLevelInstance->GetContainerEntityId()); - transformComponent->UpdateCachedWorldTransform(); + AzToolsFramework::Components::TransformComponent* transformComponent = + entity->FindComponent(); + if (transformComponent) + { + bool onlySetIfInvalid = true; + auto parentId = transformComponent->GetParentId(); + if (parentId.IsValid()) + { + auto parentAlias = m_aliasIdMapper.find(TemplateEntityIdPair(topLevelInstance->GetTemplateId(), parentId)); + if (parentAlias != m_aliasIdMapper.end()) + { + // Set the container's parent to this entity's parent, and set this entity's parent to the container + // (i.e. go from A->B to A->container->B) + auto newParentId = topLevelInstance->GetEntityId(parentAlias->second); + SetParentEntity(containerEntity->get(), newParentId, false); + onlySetIfInvalid = false; + } + } + + SetParentEntity(*entity, containerEntityId, onlySetIfInvalid); + } + } + + // Replace all the entities in the instance with the new patched ones. + // (This is easier than trying to figure out what the patched data changes are - we can let the JSON patch handle it for us) + nestedInstance->RemoveNestedEntities( + [](const AZStd::unique_ptr&) + { + return true; + }); + for (auto& entity : instantiated->m_entities) + { + auto entityAlias = m_aliasIdMapper.find(TemplateEntityIdPair(nestedInstance->GetTemplateId(), entity->GetId())); + if (entityAlias != m_aliasIdMapper.end()) + { + nestedInstance->AddEntity(*entity, entityAlias->second); + } + else + { + AZ_Assert(false, "Failed to find entity alias."); + nestedInstance->AddEntity(*entity); + } + } + + // Set the container entity of the nested prefab to have the top-level prefab as the parent if it hasn't already gotten + // another entity as its parent. + { + constexpr bool onlySetIfInvalid = true; + SetParentEntity(containerEntity->get(), topLevelInstance->GetContainerEntityId(), onlySetIfInvalid); } // Add the nested instance itself to the top-level prefab. To do this, we need to add it to our top-level instance, @@ -395,7 +531,22 @@ namespace AZ AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomBefore; instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomBefore, *topLevelInstance); - AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance)); + // When creating the new instance, we would like to have deterministic instance aliases. Prefabs that depend on this one + // will have patches that reference the alias, so if we reconvert this slice a second time, we would like it to produce + // the same results. To get a deterministic and unique alias, we rely on the slice instance. The slice instance contains + // a map of slice entity IDs to unique instance entity IDs. We'll just consistently use the first entry in the map as the + // unique instance ID. + AZStd::string instanceAlias; + auto entityIdMap = instance.GetEntityIdMap(); + if (!entityIdMap.empty()) + { + instanceAlias = AZStd::string::format("Instance_%s", entityIdMap.begin()->second.ToString().c_str()); + } + else + { + instanceAlias = AZStd::string::format("Instance_%s", AZ::Entity::MakeId().ToString().c_str()); + } + AzToolsFramework::Prefab::Instance& addedInstance = topLevelInstance->AddInstance(AZStd::move(nestedInstance), instanceAlias); AzToolsFramework::Prefab::PrefabDom topLevelInstanceDomAfter; instanceToTemplateInterface->GenerateDomForInstance(topLevelInstanceDomAfter, *topLevelInstance); @@ -418,9 +569,26 @@ namespace AZ AzToolsFramework::Prefab::InvalidLinkId); prefabSystemComponentInterface->PropagateTemplateChanges(topLevelInstance->GetTemplateId()); + AZ::Interface::Get()->UpdateTemplateInstancesInQueue(); + return true; } + void SliceConverter::SetParentEntity(const AZ::Entity& entity, const AZ::EntityId& parentId, bool onlySetIfInvalid) + { + AzToolsFramework::Components::TransformComponent* transformComponent = + entity.FindComponent(); + if (transformComponent) + { + // Only set the parent if we didn't set the onlySetIfInvalid flag, or if we did and the parent is currently invalid + if (!onlySetIfInvalid || !transformComponent->GetParentId().IsValid()) + { + transformComponent->SetParent(parentId); + transformComponent->UpdateCachedWorldTransform(); + } + } + } + void SliceConverter::PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId) { auto prefabSystemComponentInterface = AZ::Interface::Get(); diff --git a/Code/Tools/SerializeContextTools/SliceConverter.h b/Code/Tools/SerializeContextTools/SliceConverter.h index bec893ff56..82dcf30383 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.h +++ b/Code/Tools/SerializeContextTools/SliceConverter.h @@ -39,24 +39,35 @@ namespace AZ class SliceConverter : public Converter { public: - static bool ConvertSliceFiles(Application& application); + bool ConvertSliceFiles(Application& application); private: - static bool ConnectToAssetProcessor(); - static void DisconnectFromAssetProcessor(); + using TemplateEntityIdPair = AZStd::pair; - static bool ConvertSliceFile(AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun); - static bool ConvertSliceToPrefab( + bool ConnectToAssetProcessor(); + void DisconnectFromAssetProcessor(); + + bool ConvertSliceFile(AZ::SerializeContext* serializeContext, const AZStd::string& slicePath, bool isDryRun); + bool ConvertSliceToPrefab( AZ::SerializeContext* serializeContext, AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity); - static void FixPrefabEntities(AZ::Entity& containerEntity, SliceComponent::EntityList& sliceEntities); - static bool ConvertNestedSlices( + void FixPrefabEntities(AZ::Entity& containerEntity, SliceComponent::EntityList& sliceEntities); + bool ConvertNestedSlices( SliceComponent* sliceComponent, AzToolsFramework::Prefab::Instance* sourceInstance, AZ::SerializeContext* serializeContext, bool isDryRun); - static bool ConvertSliceInstance( + bool ConvertSliceInstance( AZ::SliceComponent::SliceInstance& instance, AZ::Data::Asset& sliceAsset, AzToolsFramework::Prefab::TemplateReference nestedTemplate, AzToolsFramework::Prefab::Instance* topLevelInstance); - static void PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId); - static bool SavePrefab(AZ::IO::PathView outputPath, AzToolsFramework::Prefab::TemplateId templateId); + void SetParentEntity(const AZ::Entity& entity, const AZ::EntityId& parentId, bool onlySetIfInvalid); + void PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId); + bool SavePrefab(AZ::IO::PathView outputPath, AzToolsFramework::Prefab::TemplateId templateId); + + // Track all of the entity IDs created and the prefab entity aliases that map to them. This mapping is used + // with nested slice conversion to remap parent entity IDs to the correct prefab entity IDs. + AZStd::unordered_map m_aliasIdMapper; + + // Track all of the created prefab template IDs on a slice conversion so that they can get removed at the end of the + // conversion for that file. + AZStd::unordered_set m_createdTemplateIds; }; } // namespace SerializeContextTools } // namespace AZ diff --git a/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h b/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h new file mode 100644 index 0000000000..166cb2abdf --- /dev/null +++ b/Code/Tools/SerializeContextTools/SliceConverterEditorEntityContextComponent.h @@ -0,0 +1,65 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include + +namespace AzToolsFramework +{ + // This class is an inelegant workaround for use by the Slice Converter to selectively disable entity add/remove logic + // during slice conversion in the EditorEntityContextComponent. Specifically, the standard versions of these methods will + // attempt to activate the entities as they're added. This is both unnecessary and undesirable during slice conversion, since + // entity activation requires a lot of subsystems to be active and valid. + // Instead, by selectively disabling this logic, the entities can remain in an initialized state, which is sufficient for conversion, + // without requiring those extra subsystems. + + // This problem also could have been solved by adding APIs to the EditorEntityContextComponent or the EntityContext, but there aren't + // any other known valid use cases for disabling this logic, so the extra APIs would simply encourage "bad behavior" by using them + // when they likely aren't necessary or desired. + + class SliceConverterEditorEntityContextComponent + : public EditorEntityContextComponent + { + public: + + AZ_COMPONENT(SliceConverterEditorEntityContextComponent, "{1CB0C38F-8E85-4422-91C6-E1F3B9B4B853}"); + + SliceConverterEditorEntityContextComponent() : EditorEntityContextComponent() {} + + // Simple API to selectively disable this logic *only* when performing slice to prefab conversion. + static void DisableOnContextEntityLogic() + { + m_enableOnContextEntityLogic = false; + } + + protected: + + void OnContextEntitiesAdded([[maybe_unused]] const EntityList& entities) override + { + if (m_enableOnContextEntityLogic) + { + EditorEntityContextComponent::OnContextEntitiesAdded(entities); + } + } + + void OnContextEntityRemoved([[maybe_unused]] const AZ::EntityId& id) override + { + if (m_enableOnContextEntityLogic) + { + EditorEntityContextComponent::OnContextEntityRemoved(id); + } + } + + // By default, act just like the EditorEntityContextComponent + static inline bool m_enableOnContextEntityLogic = true; + }; +} // namespace AzToolsFramework diff --git a/Code/Tools/SerializeContextTools/main.cpp b/Code/Tools/SerializeContextTools/main.cpp index d9f2cfbcc2..28eeb5ebe8 100644 --- a/Code/Tools/SerializeContextTools/main.cpp +++ b/Code/Tools/SerializeContextTools/main.cpp @@ -125,7 +125,8 @@ int main(int argc, char** argv) } else if (AZ::StringFunc::Equal("convert-slice", action.c_str())) { - result = SliceConverter::ConvertSliceFiles(application); + SliceConverter sliceConverter; + result = sliceConverter.ConvertSliceFiles(application); } else { diff --git a/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake b/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake index 814c55ea08..3427357149 100644 --- a/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake +++ b/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake @@ -17,6 +17,7 @@ set(FILES Dumper.h Dumper.cpp main.cpp + SliceConverterEditorEntityContextComponent.h SliceConverter.h SliceConverter.cpp Utilities.h diff --git a/Gems/Camera/Code/Source/CameraComponentController.cpp b/Gems/Camera/Code/Source/CameraComponentController.cpp index d0a124067b..cad666c1cd 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.cpp +++ b/Gems/Camera/Code/Source/CameraComponentController.cpp @@ -178,7 +178,10 @@ namespace Camera if ((!m_viewSystem)||(!m_system)) { // perform first-time init - m_system = gEnv->pSystem; + if (gEnv) + { + m_system = gEnv->pSystem; + } if (m_system) { // Initialize local view. diff --git a/Registry/gem_autoload.serializecontexttools.setreg b/Registry/gem_autoload.serializecontexttools.setreg index e7e88dd6a6..0f74355084 100644 --- a/Registry/gem_autoload.serializecontexttools.setreg +++ b/Registry/gem_autoload.serializecontexttools.setreg @@ -10,6 +10,9 @@ "PythonAssetBuilder.Editor": { "AutoLoad": false }, + "AWSCore": { + "AutoLoad": false + }, "AWSCore.Editor": { "AutoLoad": false }, @@ -21,6 +24,9 @@ }, "AWSMetrics": { "AutoLoad": false + }, + "AWSMetrics.Editor": { + "AutoLoad": false } } } From fda28bb7b2504e7b2d2fc7cbdd344f373bf957ef Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Thu, 3 Jun 2021 14:02:40 -0700 Subject: [PATCH 080/153] LYN-1818 | [USE CASE] Reparenting between different prefab instances by drag/drop in the Outliner (#1088) * Add the last known parent to the prefab undo cache to detect changes in the owning instance. Still WIP. * Progress in handling reparenting. Still WIP, need a change in CreateLink that will be addressed in a separate branch and then merged back. * A few fixes, reparenting now works with entities. Still working on instances. * Fix assert crashing the Editor because of the arguments being in the wrong order. * Handle moving the patches when removing and recreating links when reparenting nested instances. * Rearrange some code to prevent including instance removal in instance update undo node, as it would be redundant and cause errors in some edge cases. * Reorder instance reparenting to account for correct order of operation during undo/redo * Fix order of operations to support multiple operations in one edit (reparenting to non-container entities while changing instance) * Add function to refresh patches on links to allow aliases to be restored correctly on reparenting. * Removed RefreshEntityPatchOnLink function. Introduced a simpler way of handling porting patches. * Removing unnecessary code that was left after testing. * Minor fixes to naming and comments. * Restore previous error, no longer printing the failed patch. * Remove unused includes. * Restore include removed by mistake. * Simplified patches retrieval by using internal function. Renamed some internal functions and variables to be more accurate. --- .../Prefab/PrefabPublicHandler.cpp | 221 +++++++++++++++--- .../Prefab/PrefabPublicHandler.h | 10 +- .../Prefab/PrefabSystemComponent.cpp | 4 +- .../Prefab/PrefabUndoCache.cpp | 24 +- .../AzToolsFramework/Prefab/PrefabUndoCache.h | 13 +- 5 files changed, 217 insertions(+), 55 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 90c3dd10ae..27c812ff9d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -297,7 +297,7 @@ namespace AzToolsFramework m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId); // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes - m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter)); + m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter), parentEntityId); return AZStd::move(patch); } @@ -595,54 +595,199 @@ namespace AzToolsFramework { // Create Undo node on entities if they belong to an instance InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId); - - if (owningInstance.has_value()) + if (!owningInstance.has_value()) { - PrefabDom afterState; - AZ::Entity* entity = GetEntityById(entityId); - if (entity) + return; + } + + AZ::Entity* entity = GetEntityById(entityId); + if (!entity) + { + m_prefabUndoCache.PurgeCache(entityId); + return; + } + + PrefabDom beforeState; + AZ::EntityId beforeParentId; + m_prefabUndoCache.Retrieve(entityId, beforeState, beforeParentId); + + PrefabDom afterState; + AZ::EntityId afterParentId; + AZ::TransformBus::EventResult(afterParentId, entityId, &AZ::TransformBus::Events::GetParentId); + + m_instanceToTemplateInterface->GenerateDomForEntity(afterState, *entity); + + PrefabDom patch; + m_instanceToTemplateInterface->GeneratePatch(patch, beforeState, afterState); + m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, entityId); + + if (patch.IsArray() && !patch.Empty() && beforeState.IsObject()) + { + bool isInstanceContainerEntity = IsInstanceContainerEntity(entityId) && !IsLevelInstanceContainerEntity(entityId); + bool isNewParentOwnedByDifferentInstance = false; + + if (beforeParentId != afterParentId) { - PrefabDom beforeState; - m_prefabUndoCache.Retrieve(entityId, beforeState); + // If the entity parent changed, verify if the owning instance changed too + InstanceOptionalReference beforeOwningInstance = m_instanceEntityMapperInterface->FindOwningInstance(beforeParentId); + InstanceOptionalReference afterOwningInstance = m_instanceEntityMapperInterface->FindOwningInstance(afterParentId); - m_instanceToTemplateInterface->GenerateDomForEntity(afterState, *entity); - - PrefabDom patch; - m_instanceToTemplateInterface->GeneratePatch(patch, beforeState, afterState); - - if (patch.IsArray() && !patch.Empty() && beforeState.IsObject()) + if (beforeOwningInstance.has_value() && afterOwningInstance.has_value() && + (&beforeOwningInstance->get() != &afterOwningInstance->get())) { - if (IsInstanceContainerEntity(entityId) && !IsLevelInstanceContainerEntity(entityId)) - { - m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, entityId); - - // Save these changes as patches to the link - PrefabUndoLinkUpdate* linkUpdate = - aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast(entityId))); - linkUpdate->SetParent(parentUndoBatch); - linkUpdate->Capture(patch, owningInstance->get().GetLinkId()); - - linkUpdate->Redo(); - } - else - { - // Update the state of the entity - PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast(entityId))); - state->SetParent(parentUndoBatch); - state->Capture(beforeState, afterState, entityId); - - state->Redo(); - } + isNewParentOwnedByDifferentInstance = true; } + } - // Update the cache - m_prefabUndoCache.Store(entityId, AZStd::move(afterState)); + if (isInstanceContainerEntity) + { + if (isNewParentOwnedByDifferentInstance) + { + Internal_HandleInstanceChange(parentUndoBatch, entity, beforeParentId, afterParentId); + + PrefabDom afterStateafterReparenting; + m_instanceToTemplateInterface->GenerateDomForEntity(afterStateafterReparenting, *entity); + + PrefabDom newPatch; + m_instanceToTemplateInterface->GeneratePatch(newPatch, afterState, afterStateafterReparenting); + m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(newPatch, entityId); + + InstanceOptionalReference owningInstanceAfterReparenting = + m_instanceEntityMapperInterface->FindOwningInstance(entityId); + + Internal_HandleContainerOverride( + parentUndoBatch, entityId, newPatch, owningInstanceAfterReparenting->get().GetLinkId()); + } + else + { + Internal_HandleContainerOverride( + parentUndoBatch, entityId, patch, owningInstance->get().GetLinkId()); + } } else { - m_prefabUndoCache.PurgeCache(entityId); + Internal_HandleEntityChange(parentUndoBatch, entityId, beforeState, afterState); + + if (isNewParentOwnedByDifferentInstance) + { + Internal_HandleInstanceChange(parentUndoBatch, entity, beforeParentId, afterParentId); + } } } + + m_prefabUndoCache.UpdateCache(entityId); + } + + void PrefabPublicHandler::Internal_HandleContainerOverride( + UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch, const LinkId linkId) + { + // Save these changes as patches to the link + PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast(entityId))); + linkUpdate->SetParent(undoBatch); + linkUpdate->Capture(patch, linkId); + + linkUpdate->Redo(); + } + + void PrefabPublicHandler::Internal_HandleEntityChange( + UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState, PrefabDom& afterState) + { + // Update the state of the entity + PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast(entityId))); + state->SetParent(undoBatch); + state->Capture(beforeState, afterState, entityId); + + state->Redo(); + } + + void PrefabPublicHandler::Internal_HandleInstanceChange( + UndoSystem::URSequencePoint* undoBatch, AZ::Entity* entity, AZ::EntityId beforeParentId, AZ::EntityId afterParentId) + { + // If the entity parent changed, verify if the owning instance changed too + InstanceOptionalReference beforeOwningInstance = m_instanceEntityMapperInterface->FindOwningInstance(beforeParentId); + InstanceOptionalReference afterOwningInstance = m_instanceEntityMapperInterface->FindOwningInstance(afterParentId); + + EntityList entities; + AZStd::vector instances; + + // Retrieve all descendant entities and instances of this entity that belonged to the same owning instance. + RetrieveAndSortPrefabEntitiesAndInstances({ entity }, beforeOwningInstance->get(), entities, instances); + + AZStd::vector> instanceUniquePtrs; + AZStd::vector> instancePatches; + + // Remove Entities and Instances from the prior instance + { + // Remove Instances + for (Instance* nestedInstance : instances) + { + auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId()); + + PrefabDom oldLinkPatches; + + if (linkRef.has_value()) + { + auto patches = linkRef->get().GetLinkPatches(); + if (patches.has_value()) + { + oldLinkPatches.CopyFrom(patches->get(), oldLinkPatches.GetAllocator()); + } + } + + auto nestedInstanceUniquePtr = beforeOwningInstance->get().DetachNestedInstance(nestedInstance->GetInstanceAlias()); + RemoveLink(nestedInstanceUniquePtr, beforeOwningInstance->get().GetTemplateId(), undoBatch); + + instancePatches.emplace_back(AZStd::make_pair(nestedInstanceUniquePtr.get(), AZStd::move(oldLinkPatches))); + instanceUniquePtrs.emplace_back(AZStd::move(nestedInstanceUniquePtr)); + } + + // Get the previous state of the prior instance for undo/redo purposes + PrefabDom beforeInstanceDomBeforeRemoval; + m_instanceToTemplateInterface->GenerateDomForInstance(beforeInstanceDomBeforeRemoval, beforeOwningInstance->get()); + + // Remove Entities + for (AZ::Entity* nestedEntity : entities) + { + beforeOwningInstance->get().DetachEntity(nestedEntity->GetId()).release(); + } + + // Create the Update node for the prior owning instance + // Instance removal will be taken care of from the RemoveLink function for undo/redo purposes + PrefabUndoHelpers::UpdatePrefabInstance( + beforeOwningInstance->get(), "Update prior prefab instance", beforeInstanceDomBeforeRemoval, undoBatch); + } + + // Add Entities and Instances to new instance + { + // Add Instances + for (auto& instanceUniquePtr : instanceUniquePtrs) + { + afterOwningInstance->get().AddInstance(AZStd::move(instanceUniquePtr)); + } + + // Create Links + for (auto& instanceInfo : instancePatches) + { + // Add a new link with the old dom + CreateLink( + *instanceInfo.first, afterOwningInstance->get().GetTemplateId(), undoBatch, + AZStd::move(instanceInfo.second)); + } + + // Get the previous state of the new instance for undo/redo purposes + PrefabDom afterInstanceDomBeforeAdd; + m_instanceToTemplateInterface->GenerateDomForInstance(afterInstanceDomBeforeAdd, afterOwningInstance->get()); + + // Add Entities + for (AZ::Entity* nestedEntity : entities) + { + afterOwningInstance->get().AddEntity(*nestedEntity); + } + + // Create the Update node for the new owning instance + PrefabUndoHelpers::UpdatePrefabInstance( + afterOwningInstance->get(), "Update new prefab instance", afterInstanceDomBeforeAdd, undoBatch); + } } bool PrefabPublicHandler::IsInstanceContainerEntity(AZ::EntityId entityId) const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index e7b6f8c932..99fe8e5b67 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -90,8 +90,8 @@ namespace AzToolsFramework /** * Creates a link between the templates of an instance and its parent. * - * \param sourceInstance The instance that corresponds to the source template of the link. - * \param targetInstance The id of the target template. + * \param sourceInstance The instance that corresponds to the source template of the link (child). + * \param targetInstance The id of the target template (parent). * \param undoBatch The undo batch to set as parent for this create link action. * \param patch The patch to store in the newly created link dom. * \param isUndoRedoSupportNeeded The flag indicating whether the link should be created with undo/redo support or not. @@ -134,6 +134,12 @@ namespace AzToolsFramework bool IsCyclicalDependencyFound( InstanceOptionalConstReference instance, const AZStd::unordered_set& templateSourcePaths); + static void Internal_HandleContainerOverride( + UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, const PrefabDom& patch, const LinkId linkId); + static void Internal_HandleEntityChange( + UndoSystem::URSequencePoint* undoBatch, AZ::EntityId entityId, PrefabDom& beforeState, PrefabDom& afterState); + void Internal_HandleInstanceChange(UndoSystem::URSequencePoint* undoBatch, AZ::Entity* entity, AZ::EntityId beforeParentId, AZ::EntityId afterParentId); + void UpdateLinkPatchesWithNewEntityAliases( PrefabDom& linkPatch, const AZStd::unordered_map& oldEntityAliases, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index c42dbe792a..5f5564b4e1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -706,14 +706,14 @@ namespace AzToolsFramework "Prefab - PrefabSystemComponent::RemoveLink - " "Failed to remove Link with Id '%llu' for Instance '%s' of source Template with Id '%llu' " "from TemplateToLinkIdsMap.", - linkId, link.GetSourceTemplateId(), link.GetInstanceName().c_str()); + linkId, link.GetInstanceName().c_str(), link.GetSourceTemplateId()); result = RemoveLinkFromTargetTemplate(linkId, link); AZ_Assert(result, "Prefab - PrefabSystemComponent::RemoveLink - " "Failed to remove Link with Id '%llu' for Instance '%s' of source Template with Id '%llu' " "from target Template with Id '%llu'.", - linkId, link.GetSourceTemplateId(), link.GetInstanceName().c_str(), link.GetTargetTemplateId()); + linkId, link.GetInstanceName().c_str(), link.GetSourceTemplateId(), link.GetTargetTemplateId()); m_linkIdMap.erase(linkId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp index 7891e2c2e0..78c76cc8e5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp @@ -73,14 +73,16 @@ namespace AzToolsFramework } PrefabDom oldData; - Retrieve(entityId, oldData); + AZ::EntityId oldParentId; + Retrieve(entityId, oldData, oldParentId); UpdateCache(entityId); PrefabDom newData; - Retrieve(entityId, newData); + AZ::EntityId newParentId; + Retrieve(entityId, newData, newParentId); - if (newData != oldData) + if (newData != oldData || oldParentId != newParentId) { // display a useful message AZ::Entity* entity = nullptr; @@ -106,7 +108,7 @@ namespace AzToolsFramework // Clear out newly generated data and // replace with original data to ensure debug mode has the same data as profile/release // in the event of the consistency check failing. - m_entitySavedStates[entityId] = AZStd::move(oldData); + m_entitySavedStates[entityId] = {AZStd::move(oldData), oldParentId}; #endif // ENABLE_UNDOCACHE_CONSISTENCY_CHECKS } @@ -140,10 +142,13 @@ namespace AzToolsFramework return; } + AZ::EntityId parentId; + AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId); + // Capture it PrefabDom entityDom; m_instanceToTemplateInterface->GenerateDomForEntity(entityDom, *entity); - m_entitySavedStates.emplace(AZStd::make_pair(entityId, AZStd::move(entityDom))); + m_entitySavedStates[entityId] = {AZStd::move(entityDom), parentId}; AZLOG("Prefab Undo", "Correctly updated cache for entity of id %llu (%s)", static_cast(entityId), entity->GetName().c_str()); @@ -155,7 +160,7 @@ namespace AzToolsFramework m_entitySavedStates.erase(entityId); } - bool PrefabUndoCache::Retrieve(const AZ::EntityId& entityId, PrefabDom& outDom) + bool PrefabUndoCache::Retrieve(const AZ::EntityId& entityId, PrefabDom& outDom, AZ::EntityId& parentId) { auto it = m_entitySavedStates.find(entityId); @@ -164,14 +169,15 @@ namespace AzToolsFramework return false; } - outDom = AZStd::move(m_entitySavedStates[entityId]); + outDom = AZStd::move(m_entitySavedStates[entityId].dom); + parentId = m_entitySavedStates[entityId].parentId; m_entitySavedStates.erase(entityId); return true; } - void PrefabUndoCache::Store(const AZ::EntityId& entityId, PrefabDom&& dom) + void PrefabUndoCache::Store(const AZ::EntityId& entityId, PrefabDom&& dom, const AZ::EntityId& parentId) { - m_entitySavedStates.emplace(AZStd::make_pair(entityId, AZStd::move(dom))); + m_entitySavedStates[entityId] = {AZStd::move(dom), parentId}; } void PrefabUndoCache::Clear() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.h index 924c93f44b..3a3ac92d7c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.h @@ -46,14 +46,19 @@ namespace AzToolsFramework void Validate(const AZ::EntityId& entityId) override; // Retrieve the last known state for an entity - bool Retrieve(const AZ::EntityId& entityId, PrefabDom& outDom); + bool Retrieve(const AZ::EntityId& entityId, PrefabDom& outDom, AZ::EntityId& parentId); // Store dom as the cached state of entityId - void Store(const AZ::EntityId& entityId, PrefabDom&& dom); + void Store(const AZ::EntityId& entityId, PrefabDom&& dom, const AZ::EntityId& parentId); private: - typedef AZStd::unordered_map EntityDomMap; - EntityDomMap m_entitySavedStates; + struct PrefabUndoCacheItem + { + PrefabDom dom; + AZ::EntityId parentId; + }; + typedef AZStd::unordered_map EntityCache; + EntityCache m_entitySavedStates; InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; From 3634277317fa1777cda9849175f1a3b0aeda1423 Mon Sep 17 00:00:00 2001 From: Eric Phister <52085794+amzn-phist@users.noreply.github.com> Date: Thu, 3 Jun 2021 16:15:46 -0500 Subject: [PATCH 081/153] Project dll is not loaded by the AP when opened from the launcher (#1123) * Fixes locating the project dll when using SDK SDK engine usage has project dll in the project build path, but searching for module filepaths for loading would have a passing SystemFile::Exists check but no full filepath was amended to the module. This causes the module to fail to load. * Fix locating project module for UnixLike platforms Fixes the issue with project-centric workflows running GameLauncher, and it opens AP which can't find the project dynamic module. From AP's perspective, the project module is not in the executable directory, which is in engine bin. The SystemFile::Exists check is true on the file because it uses the 'cwd'. In that situation, an absolute path must be obtained for the module to be loaded. * Add missing header to fix UnixLike builds * Applies a suggested change from PR Use operator-> on the AZStd::optional * Add semicolon to a class macro line Prevent auto formatting indenting the following line. --- .../Module/DynamicModuleHandle_UnixLike.cpp | 23 +++++++++++++------ .../Module/DynamicModuleHandle_WinAPI.cpp | 16 ++++++++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp index 8e2b40aaca..f9da818b4f 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp @@ -13,9 +13,10 @@ #include #include #include - #include #include +#include + #include #include @@ -61,10 +62,11 @@ namespace AZ // If it doesn't attempt to append the path to the executable path if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str())) { - auto candidatePath = Platform::GetModulePath() / fullFilePath; + AZ::IO::FixedMaxPath candidatePath = Platform::GetModulePath() / fullFilePath; if (AZ::IO::SystemFile::Exists(candidatePath.c_str())) { - fullFilePath = candidatePath; + m_fileName.assign(candidatePath.Native().c_str(), candidatePath.Native().size()); + return; } } @@ -74,19 +76,26 @@ namespace AZ { if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - if(AZ::IO::FixedMaxPath projectModulePath; + if (AZ::IO::FixedMaxPath projectModulePath; settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) { projectModulePath /= fullFilePath; if (AZ::IO::SystemFile::Exists(projectModulePath.c_str())) { - fullFilePath = projectModulePath; + m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size()); } } } } - - m_fileName = AZStd::string_view{fullFilePath.Native()}; + else + { + // The module does exist (in 'cwd'), but still needs to be an absolute path for the module to be loaded. + AZStd::optional absPathOptional = AZ::Utils::ConvertToAbsolutePath(m_fileName); + if (absPathOptional.has_value()) + { + m_fileName.assign(absPathOptional->c_str(), absPathOptional->size()); + } + } } ~DynamicModuleHandleUnixLike() override diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp index 9daabfb86b..aeb8a81d09 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp @@ -24,9 +24,9 @@ namespace AZ : public DynamicModuleHandle { public: - AZ_CLASS_ALLOCATOR(DynamicModuleHandleWindows, OSAllocator, 0) + AZ_CLASS_ALLOCATOR(DynamicModuleHandleWindows, OSAllocator, 0); - DynamicModuleHandleWindows(const char* fullFileName) + DynamicModuleHandleWindows(const char* fullFileName) : DynamicModuleHandle(fullFileName) , m_handle(nullptr) { @@ -52,6 +52,7 @@ namespace AZ if (AZ::IO::SystemFile::Exists(candidatePath.c_str())) { m_fileName.assign(candidatePath.Native().c_str(), candidatePath.Native().size()); + return; } } } @@ -65,7 +66,7 @@ namespace AZ // Therefore an existence check is needed if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - if(AZ::IO::FixedMaxPath projectModulePath; + if (AZ::IO::FixedMaxPath projectModulePath; settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) { projectModulePath /= AZStd::string_view(m_fileName); @@ -76,6 +77,15 @@ namespace AZ } } } + else + { + // The module does exist (in 'cwd'), but still needs to be an absolute path for the module to be loaded. + AZStd::optional absPathOptional = AZ::Utils::ConvertToAbsolutePath(m_fileName); + if (absPathOptional.has_value()) + { + m_fileName.assign(absPathOptional->c_str(), absPathOptional->size()); + } + } } ~DynamicModuleHandleWindows() override From d1f23aff62c4644ba7b3f9f8386c8014479f8b3b Mon Sep 17 00:00:00 2001 From: jckand-amzn Date: Thu, 3 Jun 2021 17:38:22 -0500 Subject: [PATCH 082/153] SPEC-7008: Excluding more main tests from Debug test runs --- .../Gem/PythonTests/editor/test_BasicEditorWorkflows.py | 5 +++++ .../largeworlds/landscape_canvas/test_GraphComponentSync.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py b/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py index b045b364a3..f65401f007 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py +++ b/AutomatedTesting/Gem/PythonTests/editor/test_BasicEditorWorkflows.py @@ -15,6 +15,7 @@ import pytest # Bail on the test if ly_test_tools doesn't exist. pytest.importorskip('ly_test_tools') import ly_test_tools.environment.file_system as file_system +import ly_test_tools._internal.pytest_plugin as internal_plugin import editor_python_test_tools.hydra_test_utils as hydra test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts") @@ -40,6 +41,10 @@ class TestBasicEditorWorkflows(object): @pytest.mark.SUITE_main def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform): + # Skip test if running against Debug build + if "debug" in internal_plugin.build_directory: + pytest.skip("Does not execute against debug builds.") + expected_lines = [ "Create and load new level: True", "New entity creation: True", diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py index 943d0cb985..e7dc046480 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_GraphComponentSync.py @@ -132,7 +132,7 @@ class TestGraphComponentSync(object): # Skip test if running against Debug build if "debug" in internal_plugin.build_directory: pytest.skip("Does not execute against debug builds.") - + cfg_args = [level] expected_lines = [ From 792176d7640d3b5ac80f8da82c9a407da3705272 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Thu, 3 Jun 2021 16:02:16 -0700 Subject: [PATCH 083/153] Cached occlusion plane corner points and AABB in the feature processor --- .../OcclusionCullingPlaneFeatureProcessor.cpp | 49 ++++++++++++++++-- .../OcclusionCullingPlaneFeatureProcessor.h | 4 ++ .../Code/Include/Atom/RPI.Public/Culling.h | 16 +++++- .../RPI/Code/Source/RPI.Public/Culling.cpp | 51 +++++-------------- 4 files changed, 76 insertions(+), 44 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp index b9866a925f..ff7c32ba08 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp @@ -33,6 +33,7 @@ namespace AZ void OcclusionCullingPlaneFeatureProcessor::Activate() { m_occlusionCullingPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize); + m_rpiOcclusionPlanes.reserve(InitialOcclusionCullingPlanesAllocationSize); EnableSceneNotification(); } @@ -48,13 +49,46 @@ namespace AZ } void OcclusionCullingPlaneFeatureProcessor::OnBeginPrepareRender() - { - AZStd::vector occlusionCullingPlanes; - for (auto& occlusionCullingPlane : m_occlusionCullingPlanes) + { + if (m_rpiListNeedsUpdate) { - occlusionCullingPlanes.push_back(occlusionCullingPlane->GetTransform()); + // rebuild the RPI occlusion list + m_rpiOcclusionPlanes.clear(); + + for (auto& occlusionCullingPlane : m_occlusionCullingPlanes) + { + if (!occlusionCullingPlane->GetEnabled()) + { + continue; + } + + RPI::CullingScene::OcclusionPlane rpiOcclusionPlane; + + static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f); + static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f); + static const Vector3 TL = Vector3(-0.5f, 0.5f, 0.0f); + static const Vector3 TR = Vector3(0.5f, 0.5f, 0.0f); + + const AZ::Transform& transform = occlusionCullingPlane->GetTransform(); + + // convert corners to world space + rpiOcclusionPlane.m_cornerBL = transform.TransformPoint(BL); + rpiOcclusionPlane.m_cornerBR = transform.TransformPoint(BR); + rpiOcclusionPlane.m_cornerTL = transform.TransformPoint(TL); + rpiOcclusionPlane.m_cornerTR = transform.TransformPoint(TR); + + // build world space AABB + AZ::Vector3 aabbMin = rpiOcclusionPlane.m_cornerBL.GetMin(rpiOcclusionPlane.m_cornerTR); + AZ::Vector3 aabbMax = rpiOcclusionPlane.m_cornerBL.GetMax(rpiOcclusionPlane.m_cornerTR); + rpiOcclusionPlane.m_aabb = Aabb::CreateFromMinMax(aabbMin, aabbMax); + + m_rpiOcclusionPlanes.push_back(rpiOcclusionPlane); + } + + GetParentScene()->GetCullingScene()->SetOcclusionPlanes(m_rpiOcclusionPlanes); + + m_rpiListNeedsUpdate = false; } - GetParentScene()->GetCullingScene()->SetOcclusionCullingPlanes(occlusionCullingPlanes); } OcclusionCullingPlaneHandle OcclusionCullingPlaneFeatureProcessor::AddOcclusionCullingPlane(const AZ::Transform& transform) @@ -63,6 +97,8 @@ namespace AZ occlusionCullingPlane->Init(GetParentScene()); occlusionCullingPlane->SetTransform(transform); m_occlusionCullingPlanes.push_back(occlusionCullingPlane); + m_rpiListNeedsUpdate = true; + return occlusionCullingPlane; } @@ -78,18 +114,21 @@ namespace AZ AZ_Assert(itEntry != m_occlusionCullingPlanes.end(), "RemoveOcclusionCullingPlane called with an occlusion plane that is not in the occlusion plane list"); m_occlusionCullingPlanes.erase(itEntry); occlusionCullingPlane = nullptr; + m_rpiListNeedsUpdate = true; } void OcclusionCullingPlaneFeatureProcessor::SetTransform(const OcclusionCullingPlaneHandle& occlusionCullingPlane, const AZ::Transform& transform) { AZ_Assert(occlusionCullingPlane.get(), "SetTransform called with an invalid handle"); occlusionCullingPlane->SetTransform(transform); + m_rpiListNeedsUpdate = true; } void OcclusionCullingPlaneFeatureProcessor::SetEnabled(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool enabled) { AZ_Assert(occlusionCullingPlane.get(), "Enable called with an invalid handle"); occlusionCullingPlane->SetEnabled(enabled); + m_rpiListNeedsUpdate = true; } void OcclusionCullingPlaneFeatureProcessor::ShowVisualization(const OcclusionCullingPlaneHandle& occlusionCullingPlane, bool showVisualization) diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h index 211254742f..8b3ac3f58d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h @@ -57,6 +57,10 @@ namespace AZ // list of occlusion planes const size_t InitialOcclusionCullingPlanesAllocationSize = 64; OcclusionCullingPlaneVector m_occlusionCullingPlanes; + + // prebuilt list of RPI scene occlusion planes + RPI::CullingScene::OcclusionPlaneVector m_rpiOcclusionPlanes; + bool m_rpiListNeedsUpdate = false; }; } // namespace Render } // namespace AZ 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 295797d2dd..2a9c133b5c 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -215,8 +215,20 @@ namespace AZ void Activate(const class Scene* parentScene); void Deactivate(); + struct OcclusionPlane + { + // World space corners of the occluson plane + Vector3 m_cornerBL; + Vector3 m_cornerBR; + Vector3 m_cornerTL; + Vector3 m_cornerTR; + + Aabb m_aabb; + }; + using OcclusionPlaneVector = AZStd::vector; + //! Sets a list of occlusion planes to be used during the culling process. - void SetOcclusionCullingPlanes(const AZStd::vector& occlusionCullingPlanes) { m_occlusionCullingPlanes = occlusionCullingPlanes; } + void SetOcclusionPlanes(const OcclusionPlaneVector& occlusionPlanes) { m_occlusionPlanes = occlusionPlanes; } //! Notifies the CullingScene that culling will begin for this frame. void BeginCulling(const AZStd::vector& views); @@ -258,7 +270,7 @@ namespace AZ AzFramework::IVisibilityScene* m_visScene = nullptr; CullingDebugContext m_debugCtx; AZStd::concurrency_checker m_cullDataConcurrencyCheck; - AZStd::vector m_occlusionCullingPlanes; + OcclusionPlaneVector m_occlusionPlanes; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 3f28805888..7ee2c4a8d2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -546,60 +546,37 @@ namespace AZ #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED // setup occlusion culling, if necessary - MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionCullingPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); + MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); if (maskedOcclusionCulling) { // frustum cull occlusion planes - using OccluderEntry = AZStd::pair; - AZStd::vector visibleOccluders; - for (const AZ::Transform& transform : m_occlusionCullingPlanes) + using VisibleOcclusionPlane = AZStd::pair; + AZStd::vector visibleOccluders; + for (const auto& occlusionPlane : m_occlusionPlanes) { - static const AZ::Vector3 BL(-0.5f, -0.5f, 0.0f); - static const AZ::Vector3 TR(0.5f, 0.5f, 0.0f); - - AZ::Vector3 P1 = transform.TransformPoint(BL); - AZ::Vector3 P2 = transform.TransformPoint(TR); - - AZ::Vector3 aabbMin = P1.GetMin(P2); - AZ::Vector3 aabbMax = P1.GetMax(P2); - - AZ::Aabb occluderAabb = Aabb::CreateFromMinMax(aabbMin, aabbMax); - if (ShapeIntersection::Overlaps(frustum, occluderAabb)) + if (ShapeIntersection::Overlaps(frustum, occlusionPlane.m_aabb)) { // occluder is visible, compute view space distance and add to list - float depth = (view.GetWorldToViewMatrix() * occluderAabb.GetMin()).GetZ(); - depth = AZStd::min(depth, (view.GetWorldToViewMatrix() * occluderAabb.GetMax()).GetZ()); + float depth = (view.GetWorldToViewMatrix() * occlusionPlane.m_aabb.GetMin()).GetZ(); + depth = AZStd::min(depth, (view.GetWorldToViewMatrix() * occlusionPlane.m_aabb.GetMax()).GetZ()); - visibleOccluders.push_back(AZStd::make_pair(transform, depth)); + visibleOccluders.push_back(AZStd::make_pair(occlusionPlane, depth)); } } // sort the occlusion planes by view space distance, front-to-back - AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const OccluderEntry& LHS, const OccluderEntry& RHS) + AZStd::sort(visibleOccluders.begin(), visibleOccluders.end(), [](const VisibleOcclusionPlane& LHS, const VisibleOcclusionPlane& RHS) { return LHS.second > RHS.second; }); - for (const OccluderEntry& occluder : visibleOccluders) + for (const VisibleOcclusionPlane& occlusionPlane: visibleOccluders) { - const AZ::Transform& transform = occluder.first; - - // find the corners of the plane - static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f); - static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f); - static const Vector3 TL = Vector3(-0.5f, 0.5f, 0.0f); - static const Vector3 TR = Vector3(0.5f, 0.5f, 0.0f); - - Vector3 planeBL = transform.TransformPoint(BL); - Vector3 planeBR = transform.TransformPoint(BR); - Vector3 planeTL = transform.TransformPoint(TL); - Vector3 planeTR = transform.TransformPoint(TR); - // convert to clip-space - Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(planeBL); - Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(planeBR); - Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(planeTL); - Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(planeTR); + Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBL); + Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBR); + Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTL); + Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTR); // store to float array float verts[16]; From 85e6d06c2c203b7883053f97e8827689e10a5ae2 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 16:09:10 -0700 Subject: [PATCH 084/153] [default_3rdparty] add 3rd party to engine registration + specific path registration fixes --- .../ProjectManager/Source/PythonBindings.cpp | 22 +++--------- scripts/o3de/o3de/manifest.py | 8 +++++ scripts/o3de/o3de/register.py | 35 +++++++++++++++---- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 7062d886da..e2c84b2b5f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -383,7 +383,7 @@ namespace O3DE::ProjectManager engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); + engineInfo.m_thirdPartyPath = Py_To_String(o3deData["default_third_party_folder"]); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); @@ -420,6 +420,7 @@ namespace O3DE::ProjectManager pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); + pybind11::str defaultThridPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); auto registrationResult = m_register.attr("register")( enginePath, // engine_path @@ -432,28 +433,15 @@ namespace O3DE::ProjectManager pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, - defaultTemplatesFolder + defaultTemplatesFolder, + pybind11::none(), // default_restricted_folder + defaultThridPartyFolder ); if (registrationResult.cast() != 0) { result = false; } - - auto manifest = m_manifest.attr("load_o3de_manifest")(); - if (pybind11::isinstance(manifest)) - { - try - { - manifest["third_party_path"] = engineInfo.m_thirdPartyPath.toStdString(); - m_manifest.attr("save_o3de_manifest")(manifest); - } - catch ([[maybe_unused]] const std::exception& e) - { - AZ_Warning("PythonBindings", false, "Failed to set third party path."); - } - } - }); return result; diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index edcd44c525..3fa21721c2 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -97,6 +97,12 @@ def get_o3de_logs_folder() -> pathlib.Path: return logs_folder +def get_o3de_third_party_folder() -> pathlib.Path: + third_party_folder = get_o3de_folder() / '3rdParty' + third_party_folder.mkdir(parents=True, exist_ok=True) + return third_party_folder + + # o3de manifest file methods def get_o3de_manifest() -> pathlib.Path: manifest_path = get_o3de_folder() / 'o3de_manifest.json' @@ -113,6 +119,7 @@ def get_o3de_manifest() -> pathlib.Path: default_gems_folder = get_o3de_gems_folder() default_templates_folder = get_o3de_templates_folder() default_restricted_folder = get_o3de_restricted_folder() + default_third_party_folder = get_o3de_third_party_folder() default_projects_restricted_folder = default_projects_folder / 'Restricted' default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) @@ -129,6 +136,7 @@ def get_o3de_manifest() -> pathlib.Path: json_data.update({'default_gems_folder': default_gems_folder.as_posix()}) json_data.update({'default_templates_folder': default_templates_folder.as_posix()}) json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) + json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()}) json_data.update({'projects': []}) json_data.update({'external_subdirectories': []}) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 68575488dc..2e37f04acf 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -486,7 +486,7 @@ def register_default_engines_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_engines_folder() if remove else default_engines_folder, - 'default_engines_folder', remove) + 'default_engines_folder') def register_default_projects_folder(json_data: dict, @@ -494,7 +494,7 @@ def register_default_projects_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_projects_folder() if remove else default_projects_folder, - 'default_projects_folder', remove) + 'default_projects_folder') def register_default_gems_folder(json_data: dict, @@ -502,7 +502,7 @@ def register_default_gems_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_gems_folder() if remove else default_gems_folder, - 'default_gems_folder', remove) + 'default_gems_folder') def register_default_templates_folder(json_data: dict, @@ -510,16 +510,22 @@ def register_default_templates_folder(json_data: dict, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_templates_folder() if remove else default_templates_folder, - 'default_templates_folder', remove) + 'default_templates_folder') def register_default_restricted_folder(json_data: dict, default_restricted_folder: str or pathlib.Path, - reset_to_default: bool = False) -> int: + remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_restricted_folder() if remove else default_restricted_folder, - 'default_restricted_folder', remove) + 'default_restricted_folder') +def register_default_third_party_folder(json_data: dict, + default_third_party_folder: str or pathlib.Path, + remove: bool = False) -> int: + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_third_party_folder() if remove else default_third_party_folder, + 'default_third_party_folder') def register(engine_path: str or pathlib.Path = None, project_path: str or pathlib.Path = None, @@ -533,6 +539,7 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, + default_third_party_folder: str or pathlib.Path = None, external_subdir_engine_path: pathlib.Path = None, external_subdir_project_path: pathlib.Path = None, remove: bool = False, @@ -553,6 +560,7 @@ def register(engine_path: str or pathlib.Path = None, :param default_gems_folder: default gems folder :param default_templates_folder: default templates folder :param default_restricted_folder: default restricted code folder + :param default_third_party_folder: default 3rd party cache folder :param external_subdir_engine_path: Path to the engine to use when registering an external subdirectory. The registration occurs in the engine.json file in this case :param external_subdir_engine_path: Path to the project to use when registering an external subdirectory. @@ -620,6 +628,9 @@ def register(engine_path: str or pathlib.Path = None, elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): result = register_default_restricted_folder(json_data, default_restricted_folder, remove) + elif isinstance(default_third_party_folder, str) or isinstance(default_third_party_folder, pathlib.PurePath): + result = register_default_third_party_folder(json_data, default_third_party_folder, remove) + # engine is done LAST # Now that everything that could have an engine context is done, if the engine is supplied that means this is # registering the engine itself @@ -712,6 +723,15 @@ def remove_invalid_o3de_objects() -> None: f" Set default {default_restricted_folder}") register(default_restricted_folder=default_restricted_folder.as_posix()) + default_third_party_folder = pathlib.Path(json_data['default_third_party_folder']).resolve() + if not default_third_party_folder.is_dir(): + default_third_party_folder = manifest.get_o3de_folder() / '3rdParty' + default_third_party_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default 3rd Party folder {default_third_party_folder} is invalid." + f" Set default {default_third_party_folder}") + register(default_third_party_folder=default_third_party_folder.as_posix()) + def _run_register(args: argparse) -> int: if args.override_home_folder: @@ -751,6 +771,7 @@ def _run_register(args: argparse) -> int: default_gems_folder=args.default_gems_folder, default_templates_folder=args.default_templates_folder, default_restricted_folder=args.default_restricted_folder, + default_third_party_folder=args.default_third_party_folder, external_subdir_engine_path=args.external_subdirectory_engine_path, external_subdir_project_path=args.external_subdirectory_project_path, remove=args.remove, @@ -804,6 +825,8 @@ def add_parser_args(parser): help='The default templates folder to register/remove.') group.add_argument('-drf', '--default-restricted-folder', type=str, required=False, help='The default restricted folder to register/remove.') + group.add_argument('-dtpf', '--default-third-party-folder', type=str, required=False, + help='The default 3rd Party folder to register/remove.') group.add_argument('-u', '--update', action='store_true', required=False, default=False, help='Refresh the repo cache.') From 816d05ef2d85843c86fd47265cc8cf1a3b55c3c5 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:16:22 -0500 Subject: [PATCH 085/153] Updating manifest.py template query functions (#1113) * Updating manifest.py template query functions The get_project_templates, get_gem_templates and get_generic_templates methods have been renamed to indicate that the methods return the templates that can be used in a create-project, create-gem and create-from-template command of the engine_template.py Updated the print_registration.py script to support outputing project specific gems and templates. Add a unit test script for the manifest.py script. Added unit test to validate the new functions: `get_templates_for_project_creation` `get_templates_for_gem_creation` `get_templates_for_generic_creation` * Implementing the project print registration methods Added implementations of the project print registration methods and tested them locally Removed implementations of the download print registration methods, since they have not went through app-sec review. * Renaming get_restricted_data to get_restricted_json_data Fixed the get_registered method in manifest.py when looking up projects * Updated the print_manifest_json_data calls to return the result --- .../ProjectManager/Source/PythonBindings.cpp | 215 ++++---- scripts/o3de/o3de/manifest.py | 97 ++-- scripts/o3de/o3de/print_registration.py | 496 +++++++++--------- scripts/o3de/tests/CMakeLists.txt | 7 + scripts/o3de/tests/unit_test_manifest.py | 111 ++++ scripts/o3de/tests/unit_test_utils.py | 2 +- 6 files changed, 542 insertions(+), 386 deletions(-) create mode 100644 scripts/o3de/tests/unit_test_manifest.py diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 7062d886da..18b29c496f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -294,7 +294,8 @@ namespace O3DE::ProjectManager RegisterThisEngine(); return result == 0 && !PyErr_Occurred(); - } catch ([[maybe_unused]] const std::exception& e) + } + catch ([[maybe_unused]] const std::exception& e) { AZ_Warning("ProjectManagerWindow", false, "Py_Initialize() failed with %s", e.what()); return false; @@ -320,25 +321,25 @@ namespace O3DE::ProjectManager bool registrationResult = true; // already registered is considered successful bool pythonResult = ExecuteWithLock( [&] + { + // check current engine path against all other registered engines + // to see if we are already registered + auto allEngines = m_manifest.attr("get_engines")(); + if (pybind11::isinstance(allEngines)) { - // check current engine path against all other registered engines - // to see if we are already registered - auto allEngines = m_manifest.attr("get_engines")(); - if (pybind11::isinstance(allEngines)) + for (auto engine : allEngines) { - for (auto engine : allEngines) + AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"])); + if (enginePath.Compare(m_enginePath) == 0) { - AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"])); - if (enginePath.Compare(m_enginePath) == 0) - { - return; - } + return; } } + } - auto result = m_register.attr("register")(m_enginePath.c_str()); - registrationResult = (result.cast() == 0); - }); + auto result = m_register.attr("register")(m_enginePath.c_str()); + registrationResult = (result.cast() == 0); + }); bool finalResult = (registrationResult && pythonResult); AZ_Assert(finalResult, "Registration of this engine failed!"); @@ -378,12 +379,12 @@ namespace O3DE::ProjectManager auto o3deData = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(o3deData)) { - engineInfo.m_path = Py_To_String(enginePath); - engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); - engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); + engineInfo.m_path = Py_To_String(enginePath); + engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); + engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); - engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); + engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); + engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "third_party_path", ""); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); @@ -391,8 +392,8 @@ namespace O3DE::ProjectManager { try { - engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0"); - engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE"); + engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); + engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); } catch ([[maybe_unused]] const std::exception& e) { @@ -416,19 +417,19 @@ namespace O3DE::ProjectManager bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) { bool result = ExecuteWithLock([&] { - pybind11::str enginePath = engineInfo.m_path.toStdString(); - pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); - pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); + pybind11::str enginePath = engineInfo.m_path.toStdString(); + pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); + pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); auto registrationResult = m_register.attr("register")( - enginePath, // engine_path - pybind11::none(), // project_path + enginePath, // engine_path + pybind11::none(), // project_path pybind11::none(), // gem_path - pybind11::none(), // external_subdir_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri + pybind11::none(), // external_subdir_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, @@ -477,12 +478,12 @@ namespace O3DE::ProjectManager QVector gems; auto result = ExecuteWithLockErrorHandling([&] + { + for (auto path : m_manifest.attr("get_engine_gems")()) { - for (auto path : m_manifest.attr("get_engine_gems")()) - { - gems.push_back(GemInfoFromPath(path)); - } - }); + gems.push_back(GemInfoFromPath(path)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -497,13 +498,13 @@ namespace O3DE::ProjectManager QVector gems; auto result = ExecuteWithLockErrorHandling([&] + { + pybind11::str pyProjectPath = projectPath.toStdString(); + for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath)) { - pybind11::str pyProjectPath = projectPath.toStdString(); - for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath)) - { - gems.push_back(GemInfoFromPath(path)); - } - }); + gems.push_back(GemInfoFromPath(path)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -518,12 +519,12 @@ namespace O3DE::ProjectManager // Retrieve the path to the cmake file that lists the enabled gems. pybind11::str enabledGemsFilename; auto result = ExecuteWithLockErrorHandling([&] - { - const pybind11::str pyProjectPath = projectPath.toStdString(); - enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")( - pybind11::none(), // project_name - pyProjectPath); // project_path - }); + { + const pybind11::str pyProjectPath = projectPath.toStdString(); + enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")( + pybind11::none(), // project_name + pyProjectPath); // project_path + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -532,13 +533,13 @@ namespace O3DE::ProjectManager // Retrieve the actual list of names from the cmake file. QVector gemNames; result = ExecuteWithLockErrorHandling([&] + { + const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename); + for (auto gemName : pyGemNames) { - const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename); - for (auto gemName : pyGemNames) - { - gemNames.push_back(Py_To_String(gemName)); - } - }); + gemNames.push_back(Py_To_String(gemName)); + } + }); if (!result.IsSuccess()) { return AZ::Failure(result.GetError().c_str()); @@ -552,13 +553,13 @@ namespace O3DE::ProjectManager bool registrationResult = false; bool result = ExecuteWithLock( [&] - { - pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath); + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath); - // Returns an exit code so boolify it then invert result - registrationResult = !pythonRegistrationResult.cast(); - }); + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); return result && registrationResult; } @@ -568,30 +569,30 @@ namespace O3DE::ProjectManager bool registrationResult = false; bool result = ExecuteWithLock( [&] - { - pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_register.attr("register")( - pybind11::none(), // engine_path - projectPath, // project_path - pybind11::none(), // gem_path - pybind11::none(), // external_subdir_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri - pybind11::none(), // default_engines_folder - pybind11::none(), // default_projects_folder - pybind11::none(), // default_gems_folder - pybind11::none(), // default_templates_folder - pybind11::none(), // default_restricted_folder - pybind11::none(), // external_subdir_engine_path - pybind11::none(), // external_subdir_project_path - true, // remove - false // force + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_register.attr("register")( + pybind11::none(), // engine_path + projectPath, // project_path + pybind11::none(), // gem_path + pybind11::none(), // external_subdir_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri + pybind11::none(), // default_engines_folder + pybind11::none(), // default_projects_folder + pybind11::none(), // default_gems_folder + pybind11::none(), // default_templates_folder + pybind11::none(), // default_restricted_folder + pybind11::none(), // external_subdir_engine_path + pybind11::none(), // external_subdir_project_path + true, // remove + false // force ); - - // Returns an exit code so boolify it then invert result - registrationResult = !pythonRegistrationResult.cast(); - }); + + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); return result && registrationResult; } @@ -649,12 +650,12 @@ namespace O3DE::ProjectManager try { // required - gemInfo.m_name = Py_To_String(data["gem_name"]); + gemInfo.m_name = Py_To_String(data["gem_name"]); // optional gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); - gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); - gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); + gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); + gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); if (data.contains("Tags")) { @@ -685,7 +686,7 @@ namespace O3DE::ProjectManager try { projectInfo.m_projectName = Py_To_String(projectData["project_name"]); - projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName); + projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); } catch ([[maybe_unused]] const std::exception& e) { @@ -727,33 +728,33 @@ namespace O3DE::ProjectManager AZ::Outcome PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath) { return ExecuteWithLockErrorHandling([&] - { - pybind11::str pyGemPath = gemPath.toStdString(); - pybind11::str pyProjectPath = projectPath.toStdString(); + { + pybind11::str pyGemPath = gemPath.toStdString(); + pybind11::str pyProjectPath = projectPath.toStdString(); - m_enableGemProject.attr("enable_gem_in_project")( - pybind11::none(), // gem name not needed as path is provided - pyGemPath, - pybind11::none(), // project name not needed as path is provided - pyProjectPath + m_enableGemProject.attr("enable_gem_in_project")( + pybind11::none(), // gem name not needed as path is provided + pyGemPath, + pybind11::none(), // project name not needed as path is provided + pyProjectPath ); - }); + }); } AZ::Outcome PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath) { return ExecuteWithLockErrorHandling([&] - { - pybind11::str pyGemPath = gemPath.toStdString(); - pybind11::str pyProjectPath = projectPath.toStdString(); + { + pybind11::str pyGemPath = gemPath.toStdString(); + pybind11::str pyProjectPath = projectPath.toStdString(); - m_disableGemProject.attr("disable_gem_in_project")( - pybind11::none(), // gem name not needed as path is provided - pyGemPath, - pybind11::none(), // project name not needed as path is provided - pyProjectPath + m_disableGemProject.attr("disable_gem_in_project")( + pybind11::none(), // gem name not needed as path is provided + pyGemPath, + pybind11::none(), // project name not needed as path is provided + pyProjectPath ); - }); + }); } bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) @@ -773,8 +774,8 @@ namespace O3DE::ProjectManager { // required templateInfo.m_displayName = Py_To_String(data["display_name"]); - templateInfo.m_name = Py_To_String(data["template_name"]); - templateInfo.m_summary = Py_To_String(data["summary"]); + templateInfo.m_name = Py_To_String(data["template_name"]); + templateInfo.m_summary = Py_To_String(data["summary"]); // optional if (data.contains("canonical_tags")) @@ -806,7 +807,7 @@ namespace O3DE::ProjectManager QVector templates; bool result = ExecuteWithLock([&] { - for (auto path : m_manifest.attr("get_project_templates")()) + for (auto path : m_manifest.attr("get_templates_for_project_creation")()) { templates.push_back(ProjectTemplateInfoFromPath(path)); } diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index edcd44c525..bcb331d9f4 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -302,64 +302,95 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list: project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] +def get_project_templates(project_path: pathlib.Path) -> list: + project_object = get_project_json_data(project_path=project_path) + return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), + project_object['templates'])) + + +def get_project_restricted(project_path: pathlib.Path) -> list: + project_object = get_project_json_data(project_path=project_path) + return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(), + project_object['restricted'])) if 'restricted' in project_object else [] + + # Combined manifest queries def get_all_projects() -> list: - projects_data = set(get_projects()) - projects_data.update(get_engine_projects()) - return list(projects_data) + projects_data = get_projects() + projects_data.extend(get_engine_projects()) + # Remove duplicates from the list + return list(dict.fromkeys(projects_data)) def get_all_gems(project_path: pathlib.Path = None) -> list: - gems_data = set(get_gems()) - gems_data.update(get_engine_gems()) + gems_data = get_gems() + gems_data.extend(get_engine_gems()) if project_path: - gems_data.update(get_project_gems(project_path)) - return list(gems_data) + gems_data.extend(get_project_gems(project_path)) + return list(dict.fromkeys(gems_data)) def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list: - external_subdirectories_data = set(get_external_subdirectories()) - external_subdirectories_data.update(get_engine_external_subdirectories()) + external_subdirectories_data = get_external_subdirectories() + external_subdirectories_data.extend(get_engine_external_subdirectories()) if project_path: - external_subdirectories_data.update(get_project_external_subdirectories(project_path)) - return list(templates_data) + external_subdirectories_data.extend(get_project_external_subdirectories(project_path)) + return list(dict.fromkeys(external_subdirectories_data)) -def get_all_templates() -> list: - templates_data = set(get_templates()) - templates_data.update(get_engine_templates()) - return list(templates_data) +def get_all_templates(project_path: pathlib.Path = None) -> list: + templates_data = get_templates() + templates_data.extend(get_engine_templates()) + if project_path: + templates_data.extend(get_project_templates(project_path)) + return list(dict.fromkeys(templates_data)) def get_all_restricted() -> list: - restricted_data = set(get_restricted()) - restricted_data.update(get_engine_restricted()) - return list(gems_data) + restricted_data = get_restricted() + restricted_data.extend(get_engine_restricted()) + if project_path: + restricted_data.extend(get_project_restricted(project_path)) + return list(dict.fromkeys(restricted_data)) # Template functions -def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element +def get_templates_for_project_creation(): project_templates = [] - for template in get_all_templates(): - if 'Project' in template: - project_templates.append(template) + for template_path in get_all_templates(): + template_path = pathlib.Path(template_path) + template_json_path = pathlib.Path(template_path) / 'template.json' + if not validation.valid_o3de_template_json(template_json_path): + continue + + project_json_path = template_path / 'Template' / 'project.json' + if validation.valid_o3de_project_json(project_json_path): + project_templates.append(template_path) return project_templates -def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element +def get_templates_for_gem_creation(): gem_templates = [] - for template in get_all_templates(): - if 'Gem' in template: - gem_templates.append(template) + for template_path in get_all_templates(): + template_path = pathlib.Path(template_path) + template_json_path = pathlib.Path(template_path) / 'template.json' + if not validation.valid_o3de_template_json(template_json_path): + continue + + gem_json_path = template_path / 'Template' / 'gem.json' + if validation.valid_o3de_gem_json(gem_json_path): + gem_templates.append(template_path) return gem_templates -def get_generic_templates(): # temporary until we have a better way to do this... maybe template_type element - generic_templates = [] - for template in get_all_templates(): - if 'Project' not in template and 'Gem' not in template: - generic_templates.append(template) - return generic_templates +def get_templates_for_generic_creation(): # temporary until we have a better way to do this... maybe template_type element + def filter_project_and_gem_templates_out(template_path, + templates_for_project_creation = get_templates_for_project_creation(), + templates_for_gem_creation = get_templates_for_gem_creation()): + template_path = pathlib.Path(template_path) + return template_path not in templates_for_project_creation and template_path not in templates_for_gem_creation + + return list(filter(filter_project_and_gem_templates_out, get_all_templates())) def get_all_restricted() -> list: @@ -515,7 +546,7 @@ def get_template_json_data(template_name: str = None, return None -def get_restricted_data(restricted_name: str = None, +def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None) -> dict or None: if not restricted_name and not restricted_path: logger.error('Must specify either a Restricted name or Restricted Path.') diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 292f2224bc..e5c7a1afc0 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -13,6 +13,7 @@ import argparse import json import hashlib import logging +import pathlib import sys import urllib.parse @@ -21,219 +22,251 @@ from o3de import manifest, validation logger = logging.getLogger() logging.basicConfig() -def print_this_engine(verbose: int) -> None: + +def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.Path: + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return None + + if not project_path: + project_path = manifest.get_registered(project_name=project_name) + if not project_path: + logger.error(f'Unable to locate project path from the registered manifest json files:' + f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json') + return None + + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return None + + return project_path + + +def print_this_engine(verbose: int) -> int: engine_data = manifest.get_this_engine() print(json.dumps(engine_data, indent=4)) + result = True if verbose > 0: - print_engines_data(engine_data) + result = print_manifest_json_data(engine_data, 'engine.json', 'This Engine', + manifest.get_engine_json_data, 'engine_path') + return 0 if result else 1 def print_engines(verbose: int) -> None: engines_data = manifest.get_engines() print(json.dumps(engines_data, indent=4)) + if verbose > 0: - print_engines_data(engines_data) + return print_manifest_json_data(engines_data, 'engine.json', 'Engines', + manifest.get_engine_json_data, 'engine_path') + return 0 -def print_projects(verbose: int) -> None: +def print_projects(verbose: int) -> int: projects_data = manifest.get_projects() print(json.dumps(projects_data, indent=4)) + if verbose > 0: - print_projects_data(projects_data) + return print_manifest_json_data(projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_gems(verbose: int) -> None: +def print_gems(verbose: int) -> int: gems_data = manifest.get_gems() print(json.dumps(gems_data, indent=4)) + if verbose > 0: - print_gems_data(gems_data) + return print_manifest_json_data(gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_templates(verbose: int) -> None: +def print_templates(verbose: int) -> int: templates_data = manifest.get_templates() print(json.dumps(templates_data, indent=4)) + if verbose > 0: - print_templates_data(templates_data) + return print_manifest_json_data(templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_restricted(verbose: int) -> None: +def print_restricted(verbose: int) -> int: restricted_data = manifest.get_restricted() print(json.dumps(restricted_data, indent=4)) - if verbose > 0: - print_restricted_data(restricted_data) -def print_engine_projects(verbose: int) -> None: + if verbose > 0: + return print_manifest_json_data(restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 + + +# Engine output methods +def print_engine_projects(verbose: int) -> int: engine_projects_data = manifest.get_engine_projects() print(json.dumps(engine_projects_data, indent=4)) + if verbose > 0: - print_projects_data(engine_projects_data) + return print_manifest_json_data(engine_projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_engine_gems(verbose: int) -> None: +def print_engine_gems(verbose: int) -> int: engine_gems_data = manifest.get_engine_gems() print(json.dumps(engine_gems_data, indent=4)) + if verbose > 0: - print_gems_data(engine_gems_data) + return print_manifest_json_data(engine_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_engine_templates(verbose: int) -> None: +def print_engine_templates(verbose: int) -> int: engine_templates_data = manifest.get_engine_templates() print(json.dumps(engine_templates_data, indent=4)) + if verbose > 0: - print_templates_data(engine_templates_data) + return print_manifest_json_data(engine_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_engine_restricted(verbose: int) -> None: +def print_engine_restricted(verbose: int) -> int: engine_restricted_data = manifest.get_engine_restricted() print(json.dumps(engine_restricted_data, indent=4)) + if verbose > 0: - print_restricted_data(engine_restricted_data) + return print_manifest_json_data(engine_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 -def print_engine_external_subdirectories(verbose: int) -> None: +def print_engine_external_subdirectories() -> int: external_subdirs_data = manifest.get_engine_external_subdirectories() print(json.dumps(external_subdirs_data, indent=4)) + return 0 -def print_all_projects(verbose: int) -> None: +# Project output methods +def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_gems_data = manifest.get_project_gems(project_path) + print(json.dumps(project_gems_data, indent=4)) + + if verbose > 0: + return print_manifest_json_data(project_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 + + +def print_project_external_subdirectories(project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + external_subdirs_data = manifest.get_project_external_subdirectories(project_path) + print(json.dumps(external_subdirs_data, indent=4)) + return 0 + + +def print_project_templates(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_templates_data = manifest.get_project_templates(project_path) + print(json.dumps(project_templates_data, indent=4)) + if verbose > 0: + return print_manifest_json_data(project_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 + + +def print_project_restricted(verbose: int, project_path: pathlib.Path, project_name: str) -> int: + project_path = get_project_path(project_path, project_name) + if not project_path: + return 1 + + project_restricted_data = manifest.get_project_restricted(project_path) + print(json.dumps(project_restricted_data, indent=4)) + if verbose > 0: + return print_manifest_json_data(project_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 + + +def print_all_projects(verbose: int) -> int: all_projects_data = manifest.get_all_projects() print(json.dumps(all_projects_data, indent=4)) + if verbose > 0: - print_projects_data(all_projects_data) + return print_manifest_json_data(all_projects_data, 'project.json', 'Projects', + manifest.get_project_json_data, 'project_path') + return 0 -def print_all_gems(verbose: int) -> None: +def print_all_gems(verbose: int) -> int: all_gems_data = manifest.get_all_gems() print(json.dumps(all_gems_data, indent=4)) + if verbose > 0: - print_gems_data(all_gems_data) + return print_manifest_json_data(all_gems_data, 'gem.json', 'Gems', + manifest.get_gem_json_data, 'gem_path') + return 0 -def print_all_templates(verbose: int) -> None: +def print_all_external_subdirectories() -> int: + all_external_subdirectories_data = manifest.get_all_external_subdirectories() + print(json.dumps(all_external_subdirectories_data, indent=4)) + return 0 + +def print_all_templates(verbose: int) -> int: all_templates_data = manifest.get_all_templates() print(json.dumps(all_templates_data, indent=4)) + if verbose > 0: - print_templates_data(all_templates_data) + return print_manifest_json_data(all_templates_data, 'template.json', 'Templates', + manifest.get_template_json_data, 'template_path') + return 0 -def print_all_restricted(verbose: int) -> None: +def print_all_restricted(verbose: int) -> int: all_restricted_data = manifest.get_all_restricted() print(json.dumps(all_restricted_data, indent=4)) + if verbose > 0: - print_restricted_data(all_restricted_data) + return print_manifest_json_data(all_restricted_data, 'restricted.json', 'Restricted', + manifest.get_restricted_json_data, 'restricted_path') + return 0 -def print_engines_data(engines_data: dict) -> None: +def print_manifest_json_data(uri_json_data: dict, json_filename: str, + print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int: print('\n') - print("Engines================================================") - for engine_object in engines_data: + print(f"{print_prefix}================================================") + for manifest_uri in uri_json_data: # if it's not local it should be in the cache - engine_uri = engine_object['path'] - parsed_uri = urllib.parse.urlparse(engine_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(engine_uri.encode()) + parsed_uri = urllib.parse.urlparse(manifest_uri) + if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: + repo_sha256 = hashlib.sha256(manifest_uri.encode()) cache_folder = manifest.get_o3de_cache_folder() - engine = cache_folder / str(repo_sha256.hexdigest() + '.json') - print(f'{engine_uri}/engine.json cached as:') + manifest_json_path = cache_folder / str(repo_sha256.hexdigest() + '.json') else: - engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json' + manifest_json_path = pathlib.Path(manifest_uri).resolve() / json_filename - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{engine_json} failed to load: {str(e)}') - else: - print(engine_json) - print(json.dumps(engine_json_data, indent=4)) - print('\n') + json_data = get_json_func(**{get_json_data_kwargs: manifest_json_path}) + if json_data: + print(manifest_json_path) + print(json.dumps(json_data, indent=4) + '\n') + return 0 -def print_projects_data(projects_data: dict) -> None: - print('\n') - print("Projects================================================") - for project_uri in projects_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(project_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(project_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - project_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - project_json = pathlib.Path(project_uri).resolve() / 'project.json' - - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{project_json} failed to load: {str(e)}') - else: - print(project_json) - print(json.dumps(project_json_data, indent=4)) - print('\n') - - -def print_gems_data(gems_data: dict) -> None: - print('\n') - print("Gems================================================") - for gem_uri in gems_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(gem_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(gem_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - gem_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - gem_json = pathlib.Path(gem_uri).resolve() / 'gem.json' - - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{gem_json} failed to load: {str(e)}') - else: - print(gem_json) - print(json.dumps(gem_json_data, indent=4)) - print('\n') - - -def print_templates_data(templates_data: dict) -> None: - print('\n') - print("Templates================================================") - for template_uri in templates_data: - # if it's not local it should be in the cache - parsed_uri = urllib.parse.urlparse(template_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - repo_sha256 = hashlib.sha256(template_uri.encode()) - cache_folder = manifest.get_o3de_cache_folder() - template_json = cache_folder / str(repo_sha256.hexdigest() + '.json') - else: - template_json = pathlib.Path(template_uri).resolve() / 'template.json' - - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{template_json} failed to load: {str(e)}') - else: - print(template_json) - print(json.dumps(template_json_data, indent=4)) - print('\n') - - -def print_repos_data(repos_data: dict) -> None: +def print_repos_data(repos_data: dict) -> int: print('\n') print("Repos================================================") cache_folder = manifest.get_o3de_cache_folder() @@ -251,29 +284,16 @@ def print_repos_data(repos_data: dict) -> None: print(cache_file) print(json.dumps(repo_json_data, indent=4)) print('\n') - - -def print_restricted_data(restricted_data: dict) -> None: - print('\n') - print("Restricted================================================") - for restricted_path in restricted_data: - restricted_json = pathlib.Path(restricted_path).resolve() / 'restricted.json' - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warn(f'{restricted_json} failed to load: {str(e)}') - else: - print(restricted_json) - print(json.dumps(restricted_json_data, indent=4)) - print('\n') + return 0 def register_show_repos(verbose: int) -> None: - repos_data = get_repos() + repos_data = manifest.get_repos() print(json.dumps(repos_data, indent=4)) + if verbose > 0: - print_repos_data(repos_data) + return print_repos_data(repos_data) == 0 + return 0 def register_show(verbose: int) -> None: @@ -281,13 +301,15 @@ def register_show(verbose: int) -> None: print(f"{manifest.get_o3de_manifest()}:") print(json.dumps(json_data, indent=4)) + result = True if verbose > 0: - print_engines_data(manifest.get_engines()) - print_projects_data(manifest.get_all_projects()) - print_gems_data(manifest.get_gems()) - print_templates_data(manifest.get_all_templates()) - print_restricted_data(manifest.get_all_restricted()) - print_repos_data(manifest.get_repos()) + result = print_manifest_json_data(manifest.get_engines()) == 0 and result + result = print_manifest_json_data(manifest.get_all_projects()) == 0 and result + result = print_manifest_json_data(manifest.get_gems()) == 0 and result + result = print_manifest_json_data(manifest.get_all_templates()) == 0 and result + result = print_manifest_json_data(manifest.get_all_restricted()) == 0 and result + result = print_repos_data(manifest.get_repos()) == 0 and result + return 0 if result else 1 def _run_register_show(args: argparse) -> int: @@ -295,75 +317,53 @@ def _run_register_show(args: argparse) -> int: manifest.override_home_folder = args.override_home_folder if args.this_engine: - print_this_engine(args.verbose) - return 0 - + return print_this_engine(args.verbose) elif args.engines: - print_engines(args.verbose) - return 0 + return print_engines(args.verbose) elif args.projects: - print_projects(args.verbose) - return 0 + return print_projects(args.verbose) elif args.gems: - print_gems(args.verbose) - return 0 + return print_gems(args.verbose) elif args.templates: - print_templates(args.verbose) - return 0 + return print_templates(args.verbose) elif args.repos: - register_show_repos(args.verbose) - return 0 + return register_show_repos(args.verbose) elif args.restricted: - print_restricted(args.verbose) - return 0 + return print_restricted(args.verbose) elif args.engine_projects: - print_engine_projects(args.verbose) - return 0 + return print_engine_projects(args.verbose) elif args.engine_gems: - print_engine_gems(args.verbose) - return 0 - elif args.engine_templates: - print_engine_templates(args.verbose) - return 0 - elif args.engine_restricted: - print_engine_restricted(args.verbose) - return 0 + return print_engine_gems(args.verbose) elif args.engine_external_subdirectories: - print_engine_external_subdirectories(args.verbose) - return 0 + return print_engine_external_subdirectories() + elif args.engine_templates: + return print_engine_templates(args.verbose) + elif args.engine_restricted: + return print_engine_restricted(args.verbose) + + elif args.project_gems: + return print_project_gems(args.verbose, args.project_path, args.project_name) + elif args.project_external_subdirectories: + return print_project_external_subdirectories(args.project_path, args.project_name) + elif args.project_templates: + return print_project_templates(args.verbose, args.project_path, args.project_name) + elif args.project_restricted: + return print_project_restricted(args.verbose, args.project_path, args.project_name) elif args.all_projects: - print_all_projects(args.verbose) - return 0 + return print_all_projects(args.verbose) elif args.all_gems: - print_all_gems(args.verbose) - return 0 + return print_all_gems(args.verbose) + elif args.all_external_subdirectories: + return print_all_external_subdirectories() elif args.all_templates: - print_all_templates(args.verbose) - return 0 + return print_all_templates(args.verbose) elif args.all_restricted: - print_all_restricted(args.verbose) - return 0 + return print_all_restricted(args.verbose) - elif args.downloadables: - print_downloadables(args.verbose) - return 0 - if args.downloadable_engines: - print_downloadable_engines(args.verbose) - return 0 - elif args.downloadable_projects: - print_downloadable_projects(args.verbose) - return 0 - elif args.downloadable_gems: - print_downloadable_gems(args.verbose) - return 0 - elif args.downloadable_templates: - print_downloadable_templates(args.verbose) - return 0 else: - register_show(args.verbose) - return 0 + return register_show(args.verbose) def add_parser_args(parser): @@ -376,78 +376,84 @@ def add_parser_args(parser): group = parser.add_mutually_exclusive_group(required=False) group.add_argument('-te', '--this-engine', action='store_true', required=False, default=False, - help='Just the local engines.') + help='Output the current engine path.') group.add_argument('-e', '--engines', action='store_true', required=False, default=False, - help='Just the local engines.') + help='Output the engines registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-p', '--projects', action='store_true', required=False, default=False, - help='Just the local projects.') + help='Output the projects registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-g', '--gems', action='store_true', required=False, default=False, - help='Just the local gems.') + help='Output the gems registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-t', '--templates', action='store_true', required=False, default=False, - help='Just the local templates.') + help='Output the templates registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-r', '--repos', action='store_true', required=False, default=False, - help='Just the local repos. Ignores repos.') + help='Output the repos registered in the global ~/.o3de/o3de_manifest.json. Ignores repos.') group.add_argument('-rs', '--restricted', action='store_true', required=False, default=False, - help='The local restricted folders.') + help='Output the restricted directories registered in the global ~/.o3de/o3de_manifest.json.') group.add_argument('-ep', '--engine-projects', action='store_true', required=False, default=False, - help='Just the local projects. Ignores repos.') + help='Output the projects registered in the current engine engine.json. Ignores repos.') group.add_argument('-eg', '--engine-gems', action='store_true', required=False, default=False, - help='Just the local gems. Ignores repos') + help='Output the gems registered in the current engine engine.json. Ignores repos') group.add_argument('-et', '--engine-templates', action='store_true', required=False, default=False, - help='Just the local templates. Ignores repos.') + help='Output the templates registered in the current engine engine.json. Ignores repos.') group.add_argument('-ers', '--engine-restricted', action='store_true', required=False, default=False, - help='The restricted folders.') - group.add_argument('-x', '--engine-external-subdirectories', action='store_true', required=False, + help='Output the restricted directories registered in the current engine engine.json.') + group.add_argument('-ees', '--engine-external-subdirectories', action='store_true', required=False, default=False, - help='The external subdirectories.') + help='Output the external subdirectories registered in the current engine engine.json.') + + group.add_argument('-pg', '--project-gems', action='store_true', + default=False, + help='Returns the gems registered with the project.json.') + group.add_argument('-pt', '--project-templates', action='store_true', + default=False, + help='Returns the templates registered with the project.json.') + group.add_argument('-prs', '--project-restricted', action='store_true', + default=False, + help='Returns the restricted directories registered with the project.json.') + group.add_argument('-pes', '--project-external-subdirectories', action='store_true', + default=False, + help='Returns the external subdirectories register with the project.json.') group.add_argument('-ap', '--all-projects', action='store_true', required=False, default=False, - help='Just the local projects. Ignores repos.') + help='Output all projects registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') group.add_argument('-ag', '--all-gems', action='store_true', required=False, default=False, - help='Just the local gems. Ignores repos') + help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos') group.add_argument('-at', '--all-templates', action='store_true', required=False, default=False, - help='Just the local templates. Ignores repos.') - group.add_argument('-ars', '--all-restricted', action='store_true', required=False, + help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.') + group.add_argument('-ares', '--all-restricted', action='store_true', required=False, default=False, - help='The restricted folders.') - - group.add_argument('-d', '--downloadables', action='store_true', required=False, + help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') + group.add_argument('-aes', '--all-external-subdirectories', action='store_true', default=False, - help='Combine all repos into a single list of resources.') - group.add_argument('-de', '--downloadable-engines', action='store_true', required=False, - default=False, - help='Combine all repos engines into a single list of resources.') - group.add_argument('-dp', '--downloadable-projects', action='store_true', required=False, - default=False, - help='Combine all repos projects into a single list of resources.') - group.add_argument('-dg', '--downloadable-gems', action='store_true', required=False, - default=False, - help='Combine all repos gems into a single list of resources.') - group.add_argument('-dt', '--downloadable-templates', action='store_true', required=False, - default=False, - help='Combine all repos templates into a single list of resources.') + help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.') parser.add_argument('-v', '--verbose', action='count', required=False, - default=0, - help='How verbose do you want the output to be.') + default=0, + help='How verbose do you want the output to be.') + + project_group = parser.add_mutually_exclusive_group(required=False) + project_group.add_argument('-pp', '--project-path', type=pathlib.Path, + help='The path to a project.') + project_group.add_argument('-pn', '--project-name', type=str, + help='The name of a project.') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, - help='By default the home folder is the user folder, override it to this folder.') + help='By default the home folder is the user folder, override it to this folder.') parser.set_defaults(func=_run_register_show) diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 0526c7740d..82b994e387 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -34,3 +34,10 @@ ly_add_pytest( TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) + +ly_add_pytest( + NAME o3de_manifest + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_manifest.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_test_manifest.py b/scripts/o3de/tests/unit_test_manifest.py new file mode 100644 index 0000000000..98430c227b --- /dev/null +++ b/scripts/o3de/tests/unit_test_manifest.py @@ -0,0 +1,111 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import manifest + + +@pytest.mark.parametrize("valid_project_json_paths, valid_gem_json_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject/Template/project.json')], + [pathlib.Path('D:/o3de/Templates/DefaultGem/Template/gem.json')]) +]) +class TestGetTemplatesForCreation: + @staticmethod + def get_templates() -> list: + return [] + + @staticmethod + def get_project_templates() -> list: + return [] + + @staticmethod + def get_engine_templates() -> list: + return [pathlib.Path('D:/o3de/Templates/DefaultProject'), pathlib.Path('D:/o3de/Templates/DefaultGem')] + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([]) + ] + ) + def test_get_templates_for_generic_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates)\ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates)\ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json,\ + patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) as validate_project_json,\ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_generic_creation() + assert templates == expected_template_paths + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject')]) + ] + ) + def test_get_templates_for_gem_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', + side_effect=validate_project_json) as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_project_creation() + assert templates == expected_template_paths + + + @pytest.mark.parametrize("expected_template_paths", [ + pytest.param([pathlib.Path('D:/o3de/Templates/DefaultGem')]) + ] + ) + def test_get_templates_for_project_creation(self, valid_project_json_paths, valid_gem_json_paths, + expected_template_paths): + def validate_project_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_project_json_paths + + def validate_gem_json(template_path) -> bool: + return pathlib.Path(template_path) in valid_gem_json_paths + + with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \ + patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ + as get_project_templates_patch, \ + patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ + as get_engine_templates_patch, \ + patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \ + patch('o3de.validation.valid_o3de_project_json', + side_effect=validate_project_json) as validate_project_json, \ + patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json: + templates = manifest.get_templates_for_gem_creation() + assert templates == expected_template_paths \ No newline at end of file diff --git a/scripts/o3de/tests/unit_test_utils.py b/scripts/o3de/tests/unit_test_utils.py index e7d59b507b..4fe22b1f72 100755 --- a/scripts/o3de/tests/unit_test_utils.py +++ b/scripts/o3de/tests/unit_test_utils.py @@ -11,7 +11,7 @@ import pytest -from . import utils +from o3de import utils @pytest.mark.parametrize( "value, expected_result", [ From deb3c5e74a9cfa1725c77711bc584952b4231a79 Mon Sep 17 00:00:00 2001 From: cgalvan Date: Thu, 3 Jun 2021 18:20:59 -0500 Subject: [PATCH 086/153] [LYN-2446] Implemented support for duplicating instances. (#1097) * [LYN-2446] Implemented support for duplicating instances. * [LYN-2446] Addressed PR feedback. * [LYN-2446] Addressed additional PR feedback. --- .../Prefab/Instance/Instance.h | 4 +- .../Instance/InstanceUpdateExecutor.cpp | 24 ++ .../Prefab/PrefabPublicHandler.cpp | 290 +++++++++++++----- .../Prefab/PrefabPublicHandler.h | 27 ++ 4 files changed, 259 insertions(+), 86 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 4a69ade6d2..d14203e2e5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -174,6 +174,8 @@ namespace AzToolsFramework static EntityAlias GenerateEntityAlias(); AliasPath GetAbsoluteInstanceAliasPath() const; + static InstanceAlias GenerateInstanceAlias(); + protected: /** * Gets the entities owned by this instance @@ -190,8 +192,6 @@ namespace AzToolsFramework bool RegisterEntity(const AZ::EntityId& entityId, const EntityAlias& entityAlias); AZStd::unique_ptr DetachEntity(const EntityAlias& entityAlias); - static InstanceAlias GenerateInstanceAlias(); - // Provide access to private data members in the serializer friend class JsonInstanceSerializer; friend class InstanceEntityIdMapper; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index e0d29f2ab1..6194adf784 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -152,6 +152,30 @@ namespace AzToolsFramework Instance::EntityList newEntities; if (PrefabDomUtils::LoadInstanceFromPrefabDom(*instanceToUpdate, newEntities, currentTemplate.GetPrefabDom())) { + // If a link was created for a nested instance before the changes were propagated, + // then we associate it correctly here + instanceToUpdate->GetNestedInstances([&](AZStd::unique_ptr& nestedInstance) { + if (nestedInstance->GetLinkId() != InvalidLinkId) + { + return; + } + + for (auto linkId : currentTemplate.GetLinks()) + { + LinkReference nestedLink = m_prefabSystemComponentInterface->FindLink(linkId); + if (!nestedLink.has_value()) + { + continue; + } + + if (nestedLink->get().GetInstanceName() == nestedInstance->GetInstanceAlias()) + { + nestedInstance->SetLinkId(linkId); + break; + } + } + }); + AzToolsFramework::EditorEntityContextRequestBus::Broadcast( &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, newEntities); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 27c812ff9d..4656dcf48f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -899,16 +899,29 @@ namespace AzToolsFramework if (!EntitiesBelongToSameInstance(entityIds)) { - return AZ::Failure(AZStd::string("Cannot duplicate multiple " - "entities belonging to different instances with one operation.")); + return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation." + "Change your selection to contain entities in the same instance.")); } // We've already verified the entities are all owned by the same instance, // so we can just retrieve our instance from the first entity in the list. - InstanceOptionalReference commonEntityOwningInstance = GetOwnerInstanceByEntityId(entityIds[0]); - AZ_Assert( - commonEntityOwningInstance.has_value(), - "Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided"); + AZ::EntityId firstEntityIdToDuplicate = entityIds[0]; + InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate); + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided.")); + } + + // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you + // cannot duplicate an instance from itself. + if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDuplicate) + { + commonOwningInstance = commonOwningInstance->get().GetParentInstance(); + } + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided.")); + } // This will cull out any entities that have ancestors in the list, since we will end up duplicating // the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances @@ -921,105 +934,63 @@ namespace AzToolsFramework { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "DuplicateEntitiesInInstance::UndoCaptureAndDuplicateEntities"); - // Take a snapshot of the instance DOM before we manipulate it - Prefab::PrefabDom instanceDomBefore; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonEntityOwningInstance->get()); - AZStd::vector entities; AZStd::vector instances; - // Gather all entities/instances in the hierarchy, but don't detach them because we are duplicating not deleting. EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet); - bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonEntityOwningInstance->get(), entities, instances); + bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); if (!success) { return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication")); } - // Make a copy of our before instance DOM where we will add our duplicated entities - Prefab::PrefabDom instanceDomAfter; + // Take a snapshot of the instance DOM before we manipulate it + PrefabDom instanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonOwningInstance->get()); + + // Make a copy of our before instance DOM where we will add our duplicated entities and/or instances + PrefabDom instanceDomAfter; instanceDomAfter.CopyFrom(instanceDomBefore, instanceDomAfter.GetAllocator()); - AZStd::unordered_map oldAliasToNewAliasMap; - AZStd::unordered_map aliasToEntityDomMap; + EntityIdList duplicatedEntityAndInstanceIds; - for (AZ::Entity* entity : entities) - { - EntityAliasOptionalReference oldAliasRef = commonEntityOwningInstance->get().GetEntityAlias(entity->GetId()); - AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM"); - EntityAlias oldAlias = oldAliasRef.value(); + // Duplicate any nested entities and instances as requested + AZStd::unordered_map newInstanceAliasToOldInstanceMap; + DuplicateNestedEntitiesInInstance(commonOwningInstance->get(), + entities, instanceDomAfter, duplicatedEntityAndInstanceIds); + DuplicateNestedInstancesInInstance(commonOwningInstance->get(), + instances, instanceDomAfter, duplicatedEntityAndInstanceIds, + newInstanceAliasToOldInstanceMap); - // Give this the outer allocator so that the memory reference will be valid when - // it gets used for AddMember - Prefab::PrefabDom entityDomBefore(&instanceDomAfter.GetAllocator()); - m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity); - - // Keep track of the old alias <-> new alias mapping for this duplicated entity - // so we can fixup references later - EntityAlias newEntityAlias = Instance::GenerateEntityAlias(); - oldAliasToNewAliasMap.insert(AZStd::make_pair(oldAlias, newEntityAlias)); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - entityDomBefore.Accept(writer); - - // Store our duplicated Entity DOM with its new alias as a string - // so that we can fixup entity alias references before adding it - // to the Entities member of our instance DOM - QString entityDomString(buffer.GetString()); - aliasToEntityDomMap.insert(AZStd::make_pair(newEntityAlias, entityDomString)); - } - - auto entitiesIter = instanceDomAfter.FindMember(PrefabDomUtils::EntitiesName); - AZ_Assert(entitiesIter != instanceDomAfter.MemberEnd(), "Instance DOM missing the Entities member."); - - // Now that all the duplicated Entity DOMs have been created, we need to iterate - // through them and replace any previous EntityAlias references with the new ones. - // These are more than just parent entity references for nested entities, this will - // also cover any EntityId references that were made in the components between them. - for (auto aliasEntityPair : aliasToEntityDomMap) - { - EntityAlias newEntityAlias = aliasEntityPair.first; - QString newEntityDomString = aliasEntityPair.second; - - // Replace all of the old alias references with the new ones - // We bookend the aliases with \" and also with a / as an extra precaution to prevent - // inadvertently replacing a matching string vs. where an actual EntityId is expected - // This will cover both cases where an alias could be used in a normal entity vs. an instance - for (auto aliasMapIter : oldAliasToNewAliasMap) - { - ReplaceOldAliases(newEntityDomString, aliasMapIter.first, aliasMapIter.second); - } - - // Create the new Entity DOM from parsing the JSON string - Prefab::PrefabDom entityDomAfter(&instanceDomAfter.GetAllocator()); - entityDomAfter.Parse(newEntityDomString.toUtf8().constData()); - - // Add the new Entity DOM to the Entities member of the instance - rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), instanceDomAfter.GetAllocator()); - entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, instanceDomAfter.GetAllocator()); - } - - PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity duplication"); + PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication"); command->SetParent(undoBatch.GetUndoBatch()); - command->Capture(instanceDomBefore, instanceDomAfter, commonEntityOwningInstance->get().GetTemplateId()); - command->RunRedo(); + command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); + command->Redo(); - EntityIdList duplicatedEntityIds; - for (auto aliasMapIter : oldAliasToNewAliasMap) + // Create links for our duplicated instances (if any were duplicated) + for (auto [newInstanceAlias, oldInstance] : newInstanceAliasToOldInstanceMap) { - EntityAlias newEntityAlias = aliasMapIter.second; + LinkId oldLinkId = oldInstance->GetLinkId(); + auto linkRef = m_prefabSystemComponentInterface->FindLink(oldLinkId); + AZ_Assert( + linkRef.has_value(), "Unable to find link with id '%llu' during instance duplication.", + oldLinkId); - AliasPath absoluteEntityPath = commonEntityOwningInstance->get().GetAbsoluteInstanceAliasPath(); - absoluteEntityPath.Append(newEntityAlias); + PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches(); + AZ_Assert( + linkPatches.has_value(), "Link with id '%llu' is missing patches.", + oldLinkId); - AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath); - duplicatedEntityIds.push_back(newEntityId); + PrefabDom linkPatchesCopy; + linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); + + m_prefabSystemComponentInterface->CreateLink( + commonOwningInstance->get().GetTemplateId(), oldInstance->GetTemplateId(), newInstanceAlias, linkPatchesCopy); } - // Select the duplicated entities - auto selectionUndo = aznew SelectionCommand(duplicatedEntityIds, "Select Duplicated Entities"); + // Select the duplicated entities/instances + auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances"); selectionUndo->SetParent(undoBatch.GetUndoBatch()); ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo); } @@ -1508,8 +1479,159 @@ namespace AzToolsFramework return true; } + void PrefabPublicHandler::DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance, + const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder, + EntityIdList& duplicatedEntityIds) + { + if (entities.empty()) + { + return; + } + + AZStd::unordered_map oldAliasToNewAliasMap; + AZStd::unordered_map aliasToEntityDomMap; + + for (AZ::Entity* entity : entities) + { + EntityAliasOptionalReference oldAliasRef = commonOwningInstance.GetEntityAlias(entity->GetId()); + AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM"); + EntityAlias oldAlias = oldAliasRef.value(); + + // Give this the outer allocator so that the memory reference will be valid when + // it gets used for AddMember + PrefabDom entityDomBefore(&domToAddDuplicatedEntitiesUnder.GetAllocator()); + m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity); + + // Keep track of the old alias <-> new alias mapping for this duplicated entity + // so we can fixup references later + EntityAlias newEntityAlias = Instance::GenerateEntityAlias(); + oldAliasToNewAliasMap.emplace(oldAlias, newEntityAlias); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + entityDomBefore.Accept(writer); + + // Store our duplicated Entity DOM with its new alias as a string + // so that we can fixup entity alias references before adding it + // to the Entities member of our instance DOM + QString entityDomString(buffer.GetString()); + aliasToEntityDomMap.emplace(newEntityAlias, entityDomString); + } + + auto entitiesIter = domToAddDuplicatedEntitiesUnder.FindMember(PrefabDomUtils::EntitiesName); + AZ_Assert(entitiesIter != domToAddDuplicatedEntitiesUnder.MemberEnd(), "Instance DOM missing the Entities member."); + + // Now that all the duplicated Entity DOMs have been created, we need to iterate + // through them and replace any previous EntityAlias references with the new ones. + // These are more than just parent entity references for nested entities, this will + // also cover any EntityId references that were made in the components between them. + for (auto [newEntityAlias, newEntityDomString] : aliasToEntityDomMap) + { + // Replace all of the old alias references with the new ones + for (auto [oldAlias, newAlias] : oldAliasToNewAliasMap) + { + ReplaceOldAliases(newEntityDomString, oldAlias, newAlias); + } + + // Create the new Entity DOM from parsing the JSON string + PrefabDom entityDomAfter(&domToAddDuplicatedEntitiesUnder.GetAllocator()); + entityDomAfter.Parse(newEntityDomString.toUtf8().constData()); + + // Add the new Entity DOM to the Entities member of the instance + rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), domToAddDuplicatedEntitiesUnder.GetAllocator()); + entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, domToAddDuplicatedEntitiesUnder.GetAllocator()); + } + + for (auto aliasMapIter : oldAliasToNewAliasMap) + { + EntityAlias newEntityAlias = aliasMapIter.second; + + AliasPath absoluteEntityPath = commonOwningInstance.GetAbsoluteInstanceAliasPath(); + absoluteEntityPath.Append(newEntityAlias); + + AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath); + duplicatedEntityIds.push_back(newEntityId); + } + } + + void PrefabPublicHandler::DuplicateNestedInstancesInInstance(Instance& commonOwningInstance, + const AZStd::vector& instances, PrefabDom& domToAddDuplicatedInstancesUnder, + EntityIdList& duplicatedEntityIds, AZStd::unordered_map& newInstanceAliasToOldInstanceMap) + { + if (instances.empty()) + { + return; + } + + AZStd::unordered_map oldInstanceAliasToNewInstanceAliasMap; + AZStd::unordered_map aliasToInstanceDomMap; + + for (auto instance : instances) + { + PrefabDom nestedInstanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(nestedInstanceDomBefore, *instance); + + // Keep track of the old alias <-> new alias mapping for this duplicated instance + // so we can fixup references later + InstanceAlias oldAlias = instance->GetInstanceAlias(); + InstanceAlias newInstanceAlias = Instance::GenerateInstanceAlias(); + oldInstanceAliasToNewInstanceAliasMap.emplace(oldAlias, newInstanceAlias); + + // Keep track of our new instance alias with the Instance it was duplicated from, + // so that after all instances are duplicated, we can go back and create links for them + newInstanceAliasToOldInstanceMap.emplace(newInstanceAlias, instance); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + nestedInstanceDomBefore.Accept(writer); + + // Store our duplicated Instance DOM with its new alias as a string + // so that we can fixup instance alias references before adding it + // to the Instances member of our instance DOM + QString instanceDomString(buffer.GetString()); + aliasToInstanceDomMap.emplace(newInstanceAlias, instanceDomString); + } + + auto instancesIter = domToAddDuplicatedInstancesUnder.FindMember(PrefabDomUtils::InstancesName); + AZ_Assert(instancesIter != domToAddDuplicatedInstancesUnder.MemberEnd(), "Instance DOM missing the Instances member."); + + // Now that all the duplicated Instance DOMs have been created, we need to iterate + // through them and replace any previous InstanceAlias references with the new ones. + for (auto [newInstanceAlias, newInstanceDomString]: aliasToInstanceDomMap) + { + // Replace all of the old alias references with the new ones + for (auto [oldAlias, newAlias] : oldInstanceAliasToNewInstanceAliasMap) + { + ReplaceOldAliases(newInstanceDomString, oldAlias, newAlias); + } + + // Create the new Instance DOM from parsing the JSON string + PrefabDom nestedInstanceDomAfter(&domToAddDuplicatedInstancesUnder.GetAllocator()); + nestedInstanceDomAfter.Parse(newInstanceDomString.toUtf8().constData()); + + // Add the new Instance DOM to the Instances member of the instance + rapidjson::Value aliasName(newInstanceAlias.c_str(), newInstanceAlias.length(), domToAddDuplicatedInstancesUnder.GetAllocator()); + instancesIter->value.AddMember(AZStd::move(aliasName), nestedInstanceDomAfter, domToAddDuplicatedInstancesUnder.GetAllocator()); + } + + for (auto aliasMapIter : oldInstanceAliasToNewInstanceAliasMap) + { + InstanceAlias newInstanceAlias = aliasMapIter.second; + + AliasPath absoluteInstancePath = commonOwningInstance.GetAbsoluteInstanceAliasPath(); + absoluteInstancePath.Append(newInstanceAlias); + + AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath); + duplicatedEntityIds.push_back(newEntityId); + } + } + void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) { + // Replace all of the old alias references with the new ones + // We bookend the aliases with \" and also with a / as an extra precaution to prevent + // inadvertently replacing a matching string vs. where an actual EntityId is expected + // This will cover both cases where an alias could be used in a normal entity vs. an instance QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 99fe8e5b67..167791d1c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -73,6 +73,33 @@ namespace AzToolsFramework InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const; + + /** + * Duplicate a list of entities owned by a common owning instance by directly + * copying/modifying their entries in the instance DOM + * + * \param commonOwningInstance The common owning instance of all the entities being duplicated. + * \param entities The list of Entities that will be duplicated. + * \param domToAddDuplicatedEntitiesUnder The DOM of the common owning instance where the duplicated + * entity DOM values will be added to. + * \param duplicatedEntityIds A list of EntityIds corresponding to the entities that were duplicated. + */ + void DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance, + const AZStd::vector& entities, PrefabDom& domToAddDuplicatedEntitiesUnder, + EntityIdList& duplicatedEntityIds); + /** + * Duplicate a list of instances owned by a common owning instance by directly + * copying/modifying their entries in the instance DOM + * + * \param commonOwningInstance The common owning instance of all the instances being duplicated. + * \param entities The list of Instances that will be duplicated. + * \param domToAddDuplicatedInstancesUnder The DOM of the common owning instance where the duplicated + * instance DOM values will be added to. + * \param duplicatedEntityIds A list of EntityIds corresponding to the instances that were duplicated. + */ + void DuplicateNestedInstancesInInstance(Instance& commonOwningInstance, + const AZStd::vector& instances, PrefabDom& domToAddDuplicatedInstancesUnder, + EntityIdList& duplicatedEntityIds, AZStd::unordered_map& newInstanceAliasToOldInstanceMap); /** * Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch. From 08a2e50ee34ad1a77009334552a1bd94a59ec7a3 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 16:28:15 -0700 Subject: [PATCH 087/153] [default_3rdparty] missed updating a call to register --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 837235cedc..ee4e30846b 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -572,6 +572,7 @@ namespace O3DE::ProjectManager pybind11::none(), // default_gems_folder pybind11::none(), // default_templates_folder pybind11::none(), // default_restricted_folder + pybind11::none(), // default_third_party_folder pybind11::none(), // external_subdir_engine_path pybind11::none(), // external_subdir_project_path true, // remove From 29ac17a090912f483ddb1d6853eea18af8058324 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:05:05 -0700 Subject: [PATCH 088/153] SPEC-7135 Provide a method to re-trigger compiler detection for changes that require it (#1092) * SPEC-7135 Provide a method to re-trigger compiler detection for changes that require it * removing check (is wrong and is not necessary) * Invert existance check * add empty lines at the end * Clean is triggering on each build * clearing if the variable is false * test code to understand what is going on... * yeap, looks good * handling "false" in linux/mac * fix for linux/mac * Fixing typos --- scripts/build/Platform/Linux/build_linux.sh | 3 +- scripts/build/Platform/Linux/clean_linux.sh | 37 ++++++++++++++++- scripts/build/Platform/Mac/build_mac.sh | 1 + scripts/build/Platform/Mac/clean_mac.sh | 37 ++++++++++++++++- .../build/Platform/Windows/build_windows.cmd | 3 +- .../build/Platform/Windows/clean_windows.cmd | 41 ++++++++++++++++++- 6 files changed, 116 insertions(+), 6 deletions(-) diff --git a/scripts/build/Platform/Linux/build_linux.sh b/scripts/build/Platform/Linux/build_linux.sh index d96fd32371..ef1b1dcb96 100755 --- a/scripts/build/Platform/Linux/build_linux.sh +++ b/scripts/build/Platform/Linux/build_linux.sh @@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_linux.sh +source $BASEDIR/clean_linux.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} @@ -46,4 +47,4 @@ fi echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS} -popd \ No newline at end of file +popd diff --git a/scripts/build/Platform/Linux/clean_linux.sh b/scripts/build/Platform/Linux/clean_linux.sh index a21527d319..a314859877 100755 --- a/scripts/build/Platform/Linux/clean_linux.sh +++ b/scripts/build/Platform/Linux/clean_linux.sh @@ -12,6 +12,16 @@ set -o errexit # exit on the first failure encountered +# Jenkins defines environment variables for parameters and passes "false" to variables +# that are not set. Here we clear them if they are false so we can also just define them +# from command line +if [[ "${CLEAN_ASSETS}" == "false" ]]; then + CLEAN_ASSETS= +fi +if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then + CLEAN_OUTPUT_DIRECTORY= +fi + if [[ -n "$CLEAN_ASSETS" ]]; then echo "[ci_build] CLEAN_ASSETS option set" for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") @@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then done fi +# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +if [[ -n "$NODE_LABEL" ]]; then + if [[ -d $OUTPUT_DIRECTORY ]]; then + pushd $OUTPUT_DIRECTORY + if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then + LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE}) + else + LAST_NODE_LABEL= + fi + # Detect if the node label has changed + if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then + echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY + CLEAN_OUTPUT_DIRECTORY=1 + fi + popd + fi +fi + if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set" if [[ -d $OUTPUT_DIRECTORY ]]; then echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\"" rm -rf ${OUTPUT_DIRECTORY} fi -fi \ No newline at end of file +fi + +mkdir -p ${OUTPUT_DIRECTORY} +# Save the node label +pushd $OUTPUT_DIRECTORY +echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE} +popd diff --git a/scripts/build/Platform/Mac/build_mac.sh b/scripts/build/Platform/Mac/build_mac.sh index 473a968d98..4a61f97fe4 100755 --- a/scripts/build/Platform/Mac/build_mac.sh +++ b/scripts/build/Platform/Mac/build_mac.sh @@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_mac.sh +source $BASEDIR/clean_mac.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} diff --git a/scripts/build/Platform/Mac/clean_mac.sh b/scripts/build/Platform/Mac/clean_mac.sh index a21527d319..a314859877 100755 --- a/scripts/build/Platform/Mac/clean_mac.sh +++ b/scripts/build/Platform/Mac/clean_mac.sh @@ -12,6 +12,16 @@ set -o errexit # exit on the first failure encountered +# Jenkins defines environment variables for parameters and passes "false" to variables +# that are not set. Here we clear them if they are false so we can also just define them +# from command line +if [[ "${CLEAN_ASSETS}" == "false" ]]; then + CLEAN_ASSETS= +fi +if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then + CLEAN_OUTPUT_DIRECTORY= +fi + if [[ -n "$CLEAN_ASSETS" ]]; then echo "[ci_build] CLEAN_ASSETS option set" for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g") @@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then done fi +# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +if [[ -n "$NODE_LABEL" ]]; then + if [[ -d $OUTPUT_DIRECTORY ]]; then + pushd $OUTPUT_DIRECTORY + if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then + LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE}) + else + LAST_NODE_LABEL= + fi + # Detect if the node label has changed + if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then + echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY + CLEAN_OUTPUT_DIRECTORY=1 + fi + popd + fi +fi + if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set" if [[ -d $OUTPUT_DIRECTORY ]]; then echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\"" rm -rf ${OUTPUT_DIRECTORY} fi -fi \ No newline at end of file +fi + +mkdir -p ${OUTPUT_DIRECTORY} +# Save the node label +pushd $OUTPUT_DIRECTORY +echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE} +popd diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 3e995e1905..474c1720df 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -13,6 +13,7 @@ REM SETLOCAL EnableDelayedExpansion CALL %~dp0env_windows.cmd +CALL %~dp0clean_windows.cmd IF NOT EXIST "%OUTPUT_DIRECTORY%" ( MKDIR %OUTPUT_DIRECTORY%. @@ -70,4 +71,4 @@ EXIT /b 0 :error POPD -EXIT /b 1 \ No newline at end of file +EXIT /b 1 diff --git a/scripts/build/Platform/Windows/clean_windows.cmd b/scripts/build/Platform/Windows/clean_windows.cmd index 38c1d45c21..60ad445d4d 100644 --- a/scripts/build/Platform/Windows/clean_windows.cmd +++ b/scripts/build/Platform/Windows/clean_windows.cmd @@ -12,6 +12,16 @@ REM SETLOCAL EnableDelayedExpansion +REM Jenkins defines environment variables for parameters and passes "false" to variables +REM that are not set. Here we clear them if they are false so we can also just define them +REM from command line +IF "%CLEAN_ASSETS%"=="false" ( + set CLEAN_ASSETS= +) +IF "%CLEAN_OUTPUT_DIRECTORY%"=="false" ( + set CLEAN_OUTPUT_DIRECTORY= +) + IF DEFINED CLEAN_ASSETS ( ECHO [ci_build] CLEAN_ASSETS option set FOR %%P in (%CMAKE_LY_PROJECTS%) do ( @@ -19,7 +29,26 @@ IF DEFINED CLEAN_ASSETS ( ECHO [ci_build] Deleting "%%P\Cache" DEL /s /q /f %%P\Cache 1>nul ) - ) + ) +) + +REM If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc +SET LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt +IF DEFINED NODE_LABEL ( + IF EXIST %OUTPUT_DIRECTORY% ( + PUSHD %OUTPUT_DIRECTORY% + IF EXIST !LAST_CONFIGURE_NODE_LABEL_FILE! ( + FOR /F "delims=" %%x in (%LAST_CONFIGURE_NODE_LABEL_FILE%) DO SET LAST_NODE_LABEL=%%x + ) ELSE ( + SET LAST_NODE_LABEL= + ) + REM Detect if the node label has changed + IF !LAST_NODE_LABEL! NEQ !NODE_LABEL! ( + ECHO [ci_build] Last run was done with node label "!LAST_NODE_LABEL!", new node label is "!NODE_LABEL!", forcing CLEAN_OUTPUT_DIRECTORY + SET CLEAN_OUTPUT_DIRECTORY=1 + ) + POPD + ) ) IF DEFINED CLEAN_OUTPUT_DIRECTORY ( @@ -28,4 +57,12 @@ IF DEFINED CLEAN_OUTPUT_DIRECTORY ( ECHO [ci_build] Deleting "%OUTPUT_DIRECTORY%" DEL /s /q /f %OUTPUT_DIRECTORY% 1>nul ) -) \ No newline at end of file +) + +IF NOT EXIST "%OUTPUT_DIRECTORY%" ( + MKDIR %OUTPUT_DIRECTORY%. +) +REM Save the node label +PUSHD %OUTPUT_DIRECTORY% +ECHO !NODE_LABEL!> !LAST_CONFIGURE_NODE_LABEL_FILE! +POPD From 4405c2275fdc38e04d3d075eaf5e4c8a0a56ea86 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 18:23:01 -0700 Subject: [PATCH 089/153] [default_3rdparty] changed CLI argument type to pathlib.Path and removed optional str type from usage --- scripts/o3de/o3de/register.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 2e37f04acf..4e73edca7f 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -521,7 +521,7 @@ def register_default_restricted_folder(json_data: dict, 'default_restricted_folder') def register_default_third_party_folder(json_data: dict, - default_third_party_folder: str or pathlib.Path, + default_third_party_folder: pathlib.Path, remove: bool = False) -> int: return register_default_o3de_object_folder(json_data, manifest.get_o3de_third_party_folder() if remove else default_third_party_folder, @@ -539,7 +539,7 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, - default_third_party_folder: str or pathlib.Path = None, + default_third_party_folder: pathlib.Path = None, external_subdir_engine_path: pathlib.Path = None, external_subdir_project_path: pathlib.Path = None, remove: bool = False, @@ -628,7 +628,7 @@ def register(engine_path: str or pathlib.Path = None, elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): result = register_default_restricted_folder(json_data, default_restricted_folder, remove) - elif isinstance(default_third_party_folder, str) or isinstance(default_third_party_folder, pathlib.PurePath): + elif default_third_party_folder: result = register_default_third_party_folder(json_data, default_third_party_folder, remove) # engine is done LAST @@ -825,7 +825,7 @@ def add_parser_args(parser): help='The default templates folder to register/remove.') group.add_argument('-drf', '--default-restricted-folder', type=str, required=False, help='The default restricted folder to register/remove.') - group.add_argument('-dtpf', '--default-third-party-folder', type=str, required=False, + group.add_argument('-dtpf', '--default-third-party-folder', type=pathlib.Path, required=False, help='The default 3rd Party folder to register/remove.') group.add_argument('-u', '--update', action='store_true', required=False, default=False, From 9e7f8e45ebb073c3cb58bb2157d7368fb77f96d0 Mon Sep 17 00:00:00 2001 From: scottr Date: Thu, 3 Jun 2021 18:23:54 -0700 Subject: [PATCH 090/153] [default_3rdparty] fixed typo --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index ee4e30846b..37e636caef 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -421,7 +421,7 @@ namespace O3DE::ProjectManager pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString(); pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); - pybind11::str defaultThridPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); + pybind11::str defaultThirdPartyFolder = engineInfo.m_thirdPartyPath.toStdString(); auto registrationResult = m_register.attr("register")( enginePath, // engine_path @@ -436,7 +436,7 @@ namespace O3DE::ProjectManager defaultGemsFolder, defaultTemplatesFolder, pybind11::none(), // default_restricted_folder - defaultThridPartyFolder + defaultThirdPartyFolder ); if (registrationResult.cast() != 0) From 2449a9322d20d8e91afd4b7cb8813fbcd628429f Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Thu, 3 Jun 2021 18:40:44 -0700 Subject: [PATCH 091/153] Changed the occlusion culling plane model to be on the XZ plane and adjusted the corner point computations --- .../Common/Assets/Models/OcclusionCullingPlane.fbx | 4 ++-- .../OcclusionCullingPlaneFeatureProcessor.cpp | 10 +++++----- Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx b/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx index b274bfa282..f91d1015f9 100644 --- a/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx +++ b/Gems/Atom/Feature/Common/Assets/Models/OcclusionCullingPlane.fbx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a1f8d75dcd85e8b4aa57f6c0c81af0300ff96915ba3c2b591095c215d5e1d8c -size 12072 +oid sha256:75cdf73fcb9698a76a38294a1cf927a4fb41a34869e0429e1f02bf8d361a7258 +size 20400 diff --git a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp index ff7c32ba08..3c61f616d9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.cpp @@ -64,18 +64,18 @@ namespace AZ RPI::CullingScene::OcclusionPlane rpiOcclusionPlane; - static const Vector3 BL = Vector3(-0.5f, -0.5f, 0.0f); - static const Vector3 BR = Vector3(0.5f, -0.5f, 0.0f); - static const Vector3 TL = Vector3(-0.5f, 0.5f, 0.0f); - static const Vector3 TR = Vector3(0.5f, 0.5f, 0.0f); + static const Vector3 BL = Vector3(-0.5f, 0.0f, -0.5f); + static const Vector3 TL = Vector3(-0.5f, 0.0f, 0.5f); + static const Vector3 TR = Vector3( 0.5f, 0.0f, 0.5f); + static const Vector3 BR = Vector3( 0.5f, 0.0f, -0.5f); const AZ::Transform& transform = occlusionCullingPlane->GetTransform(); // convert corners to world space rpiOcclusionPlane.m_cornerBL = transform.TransformPoint(BL); - rpiOcclusionPlane.m_cornerBR = transform.TransformPoint(BR); rpiOcclusionPlane.m_cornerTL = transform.TransformPoint(TL); rpiOcclusionPlane.m_cornerTR = transform.TransformPoint(TR); + rpiOcclusionPlane.m_cornerBR = transform.TransformPoint(BR); // build world space AABB AZ::Vector3 aabbMin = rpiOcclusionPlane.m_cornerBL.GetMin(rpiOcclusionPlane.m_cornerTR); 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 2a9c133b5c..2354a4feea 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -219,9 +219,9 @@ namespace AZ { // World space corners of the occluson plane Vector3 m_cornerBL; - Vector3 m_cornerBR; Vector3 m_cornerTL; Vector3 m_cornerTR; + Vector3 m_cornerBR; Aabb m_aabb; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 7ee2c4a8d2..9f0a17f294 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -574,18 +574,18 @@ namespace AZ { // convert to clip-space Vector4 projectedBL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBL); - Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBR); Vector4 projectedTL = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTL); Vector4 projectedTR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerTR); + Vector4 projectedBR = view.GetWorldToClipMatrix() * Vector4(occlusionPlane.first.m_cornerBR); // store to float array float verts[16]; projectedBL.StoreToFloat4(&verts[0]); - projectedBR.StoreToFloat4(&verts[4]); - projectedTL.StoreToFloat4(&verts[8]); - projectedTR.StoreToFloat4(&verts[12]); + projectedTL.StoreToFloat4(&verts[4]); + projectedTR.StoreToFloat4(&verts[8]); + projectedBR.StoreToFloat4(&verts[12]); - static uint32_t indices[6] = { 0, 2, 1, 2, 3, 1 }; + static uint32_t indices[6] = { 0, 1, 2, 2, 3, 0 }; // render into the occlusion buffer, specifying BACKFACE_NONE so it functions as a double-sided occluder maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE); From fe98c34f5060ffe9053932eb0b71838d494787dc Mon Sep 17 00:00:00 2001 From: rhongAMZ <69218254+rhongAMZ@users.noreply.github.com> Date: Thu, 3 Jun 2021 19:59:29 -0700 Subject: [PATCH 092/153] EMFX - Refactor the emfx actor asset loading. (#1101) Refactor emfx asset loading. The mesh asset, skinMetaAsset and morphTargetMeta asset are part of the dependency. --- .../CommandSystem/Source/ImporterCommands.cpp | 5 +- .../RCExt/Actor/ActorGroupExporter.cpp | 52 +++-- .../Pipeline/RCExt/Actor/ActorGroupExporter.h | 3 + .../EMotionFX/Code/EMotionFX/Source/Actor.cpp | 183 ++++++------------ Gems/EMotionFX/Code/EMotionFX/Source/Actor.h | 43 ++-- .../Source/Integration/Assets/ActorAsset.cpp | 3 + .../Integration/Components/ActorComponent.cpp | 46 +---- .../Integration/Components/ActorComponent.h | 4 - .../Components/EditorActorComponent.cpp | 39 +--- .../Editor/Components/EditorActorComponent.h | 4 - 10 files changed, 137 insertions(+), 245 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp index ff05b603c0..08e1ddbb08 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/ImporterCommands.cpp @@ -94,8 +94,9 @@ namespace CommandSystem return false; } - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + // Because the actor is directly loaded from disk (without going through an actor asset), we need to ask for a blocking + // load for the asset that actor is depend on. + actor->Finalize(EMotionFX::Actor::LoadRequirement::RequireBlockingLoad); // set the actor id in case we have specified it as parameter if (actorID != MCORE_INVALIDINDEX32) diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp index c7c6b86aea..d5f53e72c5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.cpp @@ -52,7 +52,7 @@ namespace EMotionFX AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(1); + serializeContext->Class()->Version(2); } } @@ -117,21 +117,6 @@ namespace EMotionFX ExporterLib::SaveActor(filename, m_actor.get(), MCore::Endian::ENDIAN_LITTLE, GetMeshAssetId(context)); -#ifdef EMOTIONFX_ACTOR_DEBUG - // Use there line to create a log file and inspect detail debug info - AZStd::string folderPath; - AzFramework::StringFunc::Path::GetFolderPath(filename.c_str(), folderPath); - AZStd::string logFilename = folderPath; - logFilename += "EMotionFXExporter_Log.txt"; - MCore::GetLogManager().CreateLogFile(logFilename.c_str()); - EMotionFX::GetImporter().SetLogDetails(true); - filename += ".xac"; - - // use this line to load the actor from the saved actor file - EMotionFX::Actor* testLoadingActor = EMotionFX::GetImporter().LoadActor(AZStd::string(filename.c_str())); - MCore::Destroy(testLoadingActor); -#endif // EMOTIONFX_ACTOR_DEBUG - static AZ::Data::AssetType emotionFXActorAssetType("{F67CC648-EA51-464C-9F5D-4A9CE41A7F86}"); // from ActorAsset.h in EMotionFX Gem AZ::SceneAPI::Events::ExportProduct& product = context.m_products.AddProduct(AZStd::move(filename), context.m_group.GetId(), emotionFXActorAssetType, AZStd::nullopt, AZStd::nullopt); @@ -141,6 +126,26 @@ namespace EMotionFX product.m_legacyPathDependencies.emplace_back(AZStd::move(materialPathReference)); } + // Mesh asset, skin meta asset and morph target meta asset are sub assets for actor asset. + // In here we set them as the dependency of the actor asset. That make sure those assets get automatically loaded before actor asset. + // Default to the first product until we are able to establish a link between mesh and actor (ATOM-13590). + const AZ::Data::AssetType assetDependencyList[] = { + azrtti_typeid(), + azrtti_typeid(), + azrtti_typeid() + }; + + for (const AZ::Data::AssetType& assetDependency : assetDependencyList) + { + AZStd::optional result = GetFirstProductByType(context, assetDependency); + if (result != AZStd::nullopt) + { + AZ::SceneAPI::Events::ExportProduct exportProduct = result.value(); + exportProduct.m_dependencyFlags = AZ::Data::ProductDependencyInfo::CreateFlags(AZ::Data::AssetLoadBehavior::PreLoad); + product.m_productDependencies.emplace_back(exportProduct); + } + } + return SceneEvents::ProcessingResult::Success; } @@ -171,5 +176,20 @@ namespace EMotionFX return AZStd::nullopt; } + + AZStd::optional ActorGroupExporter::GetFirstProductByType( + const ActorGroupExportContext& context, AZ::Data::AssetType type) + { + const AZStd::vector& products = context.m_products.GetProducts(); + for (const AZ::SceneAPI::Events::ExportProduct& product : products) + { + if (product.m_assetType == type) + { + return product; + } + } + + return AZStd::nullopt; + } } // namespace Pipeline } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h index 451d1f4bb4..585126c07b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Actor/ActorGroupExporter.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -44,6 +45,8 @@ namespace EMotionFX //! Get the mesh asset id to which the actor is linked to by default. AZStd::optional GetMeshAssetId(const ActorGroupExportContext& context) const; + static AZStd::optional GetFirstProductByType( + const ActorGroupExportContext& context, AZ::Data::AssetType type); AutoRegisteredActor m_actor; AZStd::vector m_actorMaterialReferences; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 403e7ec05a..67f0773aec 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -125,7 +125,6 @@ namespace EMotionFX Actor::~Actor() { - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorDestroyed, this); GetEventManager().OnDeleteActor(this); @@ -1463,108 +1462,78 @@ namespace EMotionFX return morphTargetMetaAssetInfo.m_assetId.IsValid(); } - void Actor::OnAssetReady(AZ::Data::Asset asset) - { - if (asset == m_meshAsset) - { - m_meshAsset = asset; - } - if (asset == m_skinMetaAsset) - { - m_skinMetaAsset = asset; - } - if (asset == m_morphTargetMetaAsset) - { - m_morphTargetMetaAsset = asset; - } - - CheckFinalizeActor(); - } - - void Actor::CheckFinalizeActor() + void Actor::Finalize(LoadRequirement loadReq) { AZStd::scoped_lock lock(m_mutex); - if (m_meshAsset.IsReady()) + // Load the mesh asset, skin meta asset and morph target asset. + // Those sub assets should have already been setup as dependency of actor asset, so they should already be loaded when we reach here. + // Only exception is that when the actor is not loaded by an actor asset, for which we need to do a blocking load. + if (m_meshAssetId.IsValid()) { - const AZ::Data::AssetId meshAssetId = m_meshAsset.GetId(); - const bool skinMetaAssetExists = DoesSkinMetaAssetExist(meshAssetId); - const bool morphTargetMetaAssetExists = DoesMorphTargetMetaAssetExist(m_meshAsset.GetId()); + // Get the mesh asset. + m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset(m_meshAssetId, AZ::Data::AssetLoadBehavior::PreLoad); - m_skinToSkeletonIndexMap.clear(); - - // Skin and morph target meta assets are ready, fill the runtime mesh data. - if ((!skinMetaAssetExists || m_skinMetaAsset.IsReady()) && - (!morphTargetMetaAssetExists || m_morphTargetMetaAsset.IsReady())) + // Get the skin meta asset. + const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId); + if (DoesSkinMetaAssetExist(m_meshAssetId) && skinMetaAssetId.IsValid()) { - // Optional, not all actors have a skinned meshes. - if (skinMetaAssetExists) + m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset( + skinMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad); + } + + // Get the morph target meta asset. + const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId); + if (DoesMorphTargetMetaAssetExist(m_meshAssetId) && morphTargetMetaAssetId.IsValid()) + { + m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset( + morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::PreLoad); + } + + if (loadReq == LoadRequirement::RequireBlockingLoad) + { + if (m_skinMetaAsset.IsLoading()) { - m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset); + m_skinMetaAsset.BlockUntilLoadComplete(); } - - ConstructMeshes(m_skinToSkeletonIndexMap); - - // Optional, not all actors have morph targets. - if (morphTargetMetaAssetExists) + if (m_morphTargetMetaAsset.IsLoading()) { - ConstructMorphTargets(); + m_morphTargetMetaAsset.BlockUntilLoadComplete(); } - else + if (m_meshAsset.IsLoading()) { - // Optional, not all actors have morph targets. - const size_t numLODLevels = m_meshAsset->GetLodAssets().size(); - mMorphSetups.Resize(numLODLevels); - for (AZ::u32 i = 0; i < numLODLevels; ++i) - { - mMorphSetups[i] = nullptr; - } + m_meshAsset.BlockUntilLoadComplete(); } - - SetActorReady(); - - // Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances. - //m_meshAsset.Release(); - //m_skinMetaAsset.Release(); - //m_morphTargetMetaAsset.Release(); } } - } - void Actor::LoadRemainingAssets() - { - // Everything is ready already or no (skeleton-only) or an invalid mesh asset assigned. Emit ready signal directly. - if (m_isReady || !m_meshAssetId.IsValid()) + if (m_meshAsset.IsReady()) { - SetActorReady(); - return; + if (m_skinMetaAsset.IsReady()) + { + m_skinToSkeletonIndexMap = ConstructSkinToSkeletonIndexMap(m_skinMetaAsset); + } + ConstructMeshes(); + + if (m_morphTargetMetaAsset.IsReady()) + { + ConstructMorphTargets(); + } + else + { + // Optional, not all actors have morph targets. + const size_t numLODLevels = m_meshAsset->GetLodAssets().size(); + mMorphSetups.Resize(numLODLevels); + for (AZ::u32 i = 0; i < numLODLevels; ++i) + { + mMorphSetups[i] = nullptr; + } + } } - LoadMeshAssetsQueued(); - } - - void Actor::OnAssetReloaded(AZ::Data::Asset asset) - { - if (asset == m_meshAsset) - { - m_meshAsset = asset; - } - if (asset == m_skinMetaAsset) - { - m_skinMetaAsset = asset; - } - if (asset == m_morphTargetMetaAsset) - { - m_morphTargetMetaAsset = asset; - } - - CheckFinalizeActor(); - } - - void Actor::SetActorReady() - { m_isReady = true; ActorNotificationBus::Broadcast(&ActorNotificationBus::Events::OnActorReady, this); + // Do not release the mesh assets. We need the mesh data to initialize future instances of the render actor instances. } // update the static AABB (very heavy as it has to create an actor instance, update mesh deformers, calculate the mesh based bounds etc) @@ -2792,37 +2761,6 @@ namespace EMotionFX m_meshAssetId = assetId; } - void Actor::LoadMeshAssetsQueued() - { - AZStd::scoped_lock lock(m_mutex); - - // Mesh asset will be queue loaded on post init. - if (m_meshAssetId.IsValid()) - { - m_isReady = false; - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); - - AZ::Data::AssetBus::MultiHandler::BusConnect(m_meshAssetId); - m_meshAsset = AZ::Data::AssetManager::Instance().GetAsset(m_meshAssetId, AZ::Data::AssetLoadBehavior::Default); - - // Skin meta asset - if (DoesSkinMetaAssetExist(m_meshAssetId)) - { - const AZ::Data::AssetId skinMetaAssetId = ConstructSkinMetaAssetId(m_meshAssetId); - AZ::Data::AssetBus::MultiHandler::BusConnect(skinMetaAssetId); - m_skinMetaAsset = AZ::Data::AssetManager::Instance().GetAsset(skinMetaAssetId, AZ::Data::AssetLoadBehavior::Default); - } - - // Morph target meta asset - if (DoesMorphTargetMetaAssetExist(m_meshAssetId)) - { - const AZ::Data::AssetId morphTargetMetaAssetId = ConstructMorphTargetMetaAssetId(m_meshAssetId); - AZ::Data::AssetBus::MultiHandler::BusConnect(morphTargetMetaAssetId); - m_morphTargetMetaAsset = AZ::Data::AssetManager::Instance().GetAsset(morphTargetMetaAssetId, AZ::Data::AssetLoadBehavior::Default); - } - } - } - Node* Actor::FindMeshJoint(const AZ::Data::Asset& lodModelAsset) const { const AZStd::array_view& sourceMeshes = lodModelAsset->GetMeshes(); @@ -2843,7 +2781,7 @@ namespace EMotionFX return mSkeleton->GetNode(0); } - void Actor::ConstructMeshes(const AZStd::unordered_map& skinToSkeletonIndexMap) + void Actor::ConstructMeshes() { AZ_Assert(m_meshAsset.IsReady(), "Mesh asset should be fully loaded and ready."); @@ -2855,7 +2793,8 @@ namespace EMotionFX SetNumLODLevels(numLODLevels, /*adjustMorphSetup=*/false); const uint32 numNodes = mSkeleton->GetNumNodes(); - // Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and GLActor. + // Remove all the materials and add them back based on the meshAsset. Eventually we will remove all the material from Actor and + // GLActor. RemoveAllMaterials(); mMaterials.Resize(numLODLevels); @@ -2866,7 +2805,7 @@ namespace EMotionFX lodLevels[lodLevel].mNodeInfos.Resize(numNodes); // Create a single mesh for the actor. - Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, skinToSkeletonIndexMap); + Mesh* mesh = Mesh::CreateFromModelLod(lodAsset, m_skinToSkeletonIndexMap); // Find an owning joint for the mesh. Node* meshJoint = FindMeshJoint(lodAsset); @@ -2896,13 +2835,14 @@ namespace EMotionFX continue; } - EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer = static_cast(vertexAttributeLayer); + EMotionFX::SkinningInfoVertexAttributeLayer* skinLayer = + static_cast(vertexAttributeLayer); const AZ::u32 numOrgVerts = skinLayer->GetNumAttributes(); AZStd::set localJointIndices = skinLayer->CalcLocalJointIndices(numOrgVerts); const AZ::u32 numLocalJoints = static_cast(localJointIndices.size()); - // The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that anymore. - // Default to dual quat skinning. + // The information about if we want to use dual quat skinning is baked into the mesh chunk and we don't have access to that + // anymore. Default to dual quat skinning. const bool dualQuatSkinning = true; if (dualQuatSkinning) { @@ -2970,7 +2910,8 @@ namespace EMotionFX void Actor::ConstructMorphTargets() { - AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(), "Mesh as well as morph target meta asset asset should be fully loaded and ready."); + AZ_Assert(m_meshAsset.IsReady() && m_morphTargetMetaAsset.IsReady(), + "Mesh as well as morph target meta asset asset should be fully loaded and ready."); AZStd::vector& lodLevels = m_meshLodData.m_lodLevels; const AZStd::array_view>& lodAssets = m_meshAsset->GetLodAssets(); const size_t numLODLevels = lodAssets.size(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h index 9bf0daf046..3fe9711f18 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.h @@ -63,7 +63,6 @@ namespace EMotionFX * still share the same data from the Actor class. The Actor contains information about the hierarchy/structure of the characters. */ class EMFX_API Actor - : private AZ::Data::AssetBus::MultiHandler { public: AZ_CLASS_ALLOCATOR_DECL @@ -101,6 +100,12 @@ namespace EMotionFX uint8 mFlags; // bitfield with MIRRORFLAG_ prefix }; + enum class LoadRequirement : bool + { + RequireBlockingLoad, + AllowAsyncLoad + }; + //------------------------------------------------ /** @@ -885,36 +890,35 @@ namespace EMotionFX bool GetOptimizeSkeleton() const { return m_optimizeSkeleton; } void SetMeshAssetId(const AZ::Data::AssetId& assetId); - void CheckFinalizeActor(); - void LoadMeshAssetsQueued(); - void LoadRemainingAssets(); + AZ::Data::AssetId GetMeshAssetId() const { return m_meshAssetId; }; const AZ::Data::Asset& GetMeshAsset() const { return m_meshAsset; } const AZ::Data::Asset& GetSkinMetaAsset() const { return m_skinMetaAsset; } const AZ::Data::Asset& GetMorphTargetMetaAsset() const { return m_morphTargetMetaAsset; } - const AZStd::unordered_map& GetSkinToSkeletonIndexMap() const { return m_skinToSkeletonIndexMap; } - void SetMeshAsset(AZ::Data::Asset asset) { m_meshAsset = asset; } - void SetSkinMetaAsset(AZ::Data::Asset asset) { m_skinMetaAsset = asset; } - void SetMorphTargetMetaAsset(AZ::Data::Asset asset) { m_morphTargetMetaAsset = asset; } + /** + * Is the actor fully ready? + * @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized. + **/ + bool IsReady() const { return m_isReady; } /** - * Is the actor fully ready? - * @result True in case the actor as well as its dependent files (e.g. mesh, skin, morph targets) are fully loaded and initialized. - **/ - bool IsReady() const { return m_isReady; } + * Finalize the actor with preload assets (mesh, skinmeta and morph target assets). + * LoadRequirement - We won't need a blocking load if the actor is part of the actor asset, as that will trigger the preload assets + * to load and get ready before finalize has been reached. + * However, if we are calling this on an actor that bypassed the asset system (e.g loading the actor directly from disk), it will require + * a blocking load. This option is now being used because emfx editor does not fully integrate with the asset system. + */ + void Finalize(LoadRequirement loadReq = LoadRequirement::AllowAsyncLoad); private: void InsertJointAndParents(AZ::u32 jointIndex, AZStd::unordered_set& includedJointIndices); - // AZ::Data::AssetBus::Handler - void OnAssetReady(AZ::Data::Asset asset) override; - void OnAssetReloaded(AZ::Data::Asset asset) override; - AZStd::unordered_map ConstructSkinToSkeletonIndexMap(const AZ::Data::Asset& skinMetaAsset); - void ConstructMeshes(const AZStd::unordered_map& skinToSkeletonIndexMap); + void ConstructMeshes(); void ConstructMorphTargets(); + Node* FindJointByMeshName(const AZStd::string_view meshName) const; // per node info (shared between lods) @@ -966,9 +970,6 @@ namespace EMotionFX Node* FindMeshJoint(const AZ::Data::Asset& lodModelAsset) const; - void SetActorReady(); - bool m_isReady = false; - Skeleton* mSkeleton; /**< The skeleton, containing the nodes and bind pose. */ MCore::Array mDependencies; /**< The dependencies on other actors (shared meshes and transforms). */ AZStd::vector mNodeInfos; /**< The per node info, shared between lods. */ @@ -992,7 +993,7 @@ namespace EMotionFX bool mDirtyFlag; /**< The dirty flag which indicates whether the user has made changes to the actor since the last file save operation. */ bool mUsedForVisualization; /**< Indicates if the actor is used for visualization specific things and is not used as a normal in-game actor. */ bool m_optimizeSkeleton; /**< Indicates if we should perform/ */ - + bool m_isReady = false; /**< If actor as well as its dependent files are fully loaded and initialized.*/ #if defined(EMFX_DEVELOPMENT_BUILD) bool mIsOwnedByRuntime; /**< Set if the actor is used/owned by the engine runtime. */ #endif // EMFX_DEVELOPMENT_BUILD diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp index 518db289e2..539b656754 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp @@ -68,6 +68,9 @@ namespace EMotionFX &actorSettings, ""); + assetData->m_emfxActor->Finalize(); + + // Clear out the EMFX raw asset data. assetData->ReleaseEMotionFXData(); if (!assetData->m_emfxActor) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 982b62fbcf..f41ef165c8 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -154,17 +154,15 @@ namespace EMotionFX Actor* actor = m_configuration.m_actorAsset->GetActor(); if (actor) { - OnActorReady(actor); + CheckActorCreation(); } } ////////////////////////////////////////////////////////////////////////// ActorComponent::ActorComponent(const Configuration* configuration) : m_debugDrawRoot(false) - , m_sceneFinishSimHandler([this]( - [[maybe_unused]] AzPhysics::SceneHandle sceneHandle, - float fixedDeltatime - ) + , m_sceneFinishSimHandler([this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle, + float fixedDeltatime) { if (m_actorInstance) { @@ -192,18 +190,9 @@ namespace EMotionFX if (cfg.m_actorAsset.GetId().IsValid()) { - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusConnect(); AZ::Data::AssetBus::Handler::BusConnect(cfg.m_actorAsset.GetId()); cfg.m_actorAsset.QueueLoad(); - - // In case the asset was already loaded fully, create the actor directly. - if (cfg.m_actorAsset.IsReady() && - cfg.m_actorAsset->GetActor()) - { - cfg.m_actorAsset->GetActor()->LoadRemainingAssets(); - } } AZ::TickBus::Handler::BusConnect(); @@ -231,7 +220,6 @@ namespace EMotionFX LmbrCentral::AttachmentComponentNotificationBus::Handler::BusDisconnect(); AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); DestroyActor(); m_configuration.m_actorAsset.Release(); @@ -314,28 +302,12 @@ namespace EMotionFX Actor* actor = m_configuration.m_actorAsset->GetActor(); AZ_Assert(m_configuration.m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid."); - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + CheckActorCreation(); } void ActorComponent::OnAssetReloaded(AZ::Data::Asset asset) { - DestroyActor(); - m_configuration.m_actorAsset = asset; - - const Actor* oldActor = m_configuration.m_actorAsset->GetActor(); - AZ::Data::Asset meshAsset = oldActor->GetMeshAsset(); - AZ::Data::Asset skinMetaAsset = oldActor->GetSkinMetaAsset(); - AZ::Data::Asset morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset(); - - m_configuration.m_actorAsset = asset; - Actor* newActor = m_configuration.m_actorAsset->GetActor(); - AZ_Assert(m_configuration.m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid."); - - newActor->SetMeshAsset(meshAsset); - newActor->SetSkinMetaAsset(skinMetaAsset); - newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset); - newActor->CheckFinalizeActor(); + OnAssetReady(asset); } bool ActorComponent::IsPhysicsSceneSimulationFinishEventConnected() const @@ -850,13 +822,5 @@ namespace EMotionFX m_actorInstance->RemoveAttachment(targetActorInstance); } } - - void ActorComponent::OnActorReady(Actor* actor) - { - if (m_configuration.m_actorAsset && m_configuration.m_actorAsset->GetActor() == actor) - { - CheckActorCreation(); - } - } } // namespace Integration } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h index 8188da19b4..4172ce63bc 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h @@ -44,7 +44,6 @@ namespace EMotionFX , private LmbrCentral::AttachmentComponentNotificationBus::Handler , private AzFramework::CharacterPhysicsDataRequestBus::Handler , private AzFramework::RagdollPhysicsNotificationBus::Handler - , private EMotionFX::ActorNotificationBus::Handler { public: AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"); @@ -168,9 +167,6 @@ namespace EMotionFX void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; int GetTickOrder() override; - // ActorNotificationBus::Handler - void OnActorReady(Actor* actor) override; - void CheckActorCreation(); void DestroyActor(); void CheckAttachToEntity(); diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index d22bb0007f..7d5b7ade00 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -156,8 +156,6 @@ namespace EMotionFX ////////////////////////////////////////////////////////////////////////// void EditorActorComponent::Activate() { - EMotionFX::ActorNotificationBus::Handler::BusConnect(); - LoadActorAsset(); const AZ::EntityId entityId = GetEntityId(); @@ -186,8 +184,6 @@ namespace EMotionFX AZ::TickBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusDisconnect(); - EMotionFX::ActorNotificationBus::Handler::BusDisconnect(); - DestroyActorInstance(); m_actorAsset.Release(); } @@ -234,13 +230,6 @@ namespace EMotionFX AZ::Data::AssetBus::Handler::BusDisconnect(); AZ::Data::AssetBus::Handler::BusConnect(m_actorAsset.GetId()); m_actorAsset.QueueLoad(); - - // In case the asset was already loaded fully, create the actor directly. - if (m_actorAsset.IsReady() && - m_actorAsset->GetActor()) - { - m_actorAsset->GetActor()->LoadRemainingAssets(); - } } else { @@ -475,27 +464,13 @@ namespace EMotionFX Actor* actor = m_actorAsset->GetActor(); AZ_Assert(m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid."); - actor->LoadRemainingAssets(); - actor->CheckFinalizeActor(); + CheckActorCreation(); } void EditorActorComponent::OnAssetReloaded(AZ::Data::Asset asset) { DestroyActorInstance(); - - const Actor* oldActor = m_actorAsset->GetActor(); - AZ::Data::Asset meshAsset = oldActor->GetMeshAsset(); - AZ::Data::Asset skinMetaAsset = oldActor->GetSkinMetaAsset(); - AZ::Data::Asset morphTargetMetaAsset = oldActor->GetMorphTargetMetaAsset(); - - m_actorAsset = asset; - Actor* newActor = m_actorAsset->GetActor(); - AZ_Assert(m_actorAsset.IsReady() && newActor, "Actor asset should be loaded and actor valid."); - - newActor->SetMeshAsset(meshAsset); - newActor->SetSkinMetaAsset(skinMetaAsset); - newActor->SetMorphTargetMetaAsset(morphTargetMetaAsset); - newActor->CheckFinalizeActor(); + OnAssetReady(asset); } void EditorActorComponent::SetActorAsset(AZ::Data::Asset actorAsset) @@ -505,7 +480,7 @@ namespace EMotionFX Actor* actor = m_actorAsset->GetActor(); if (actor) { - OnActorReady(actor); + CheckActorCreation(); } } @@ -818,14 +793,6 @@ namespace EMotionFX return false; } - void EditorActorComponent::OnActorReady(Actor* actor) - { - if (m_actorAsset && m_actorAsset->GetActor() == actor) - { - CheckActorCreation(); - } - } - void EditorActorComponent::CheckActorCreation() { // Enable/disable debug drawing. diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h index 8ddd95c3b7..5dabbe4ada 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h @@ -45,7 +45,6 @@ namespace EMotionFX , private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler , private AzToolsFramework::EditorVisibilityNotificationBus::Handler , public AzFramework::BoundsRequestBus::Handler - , private EMotionFX::ActorNotificationBus::Handler { public: AZ_EDITOR_COMPONENT(EditorActorComponent, "{A863EE1B-8CFD-4EDD-BA0D-1CEC2879AD44}"); @@ -142,9 +141,6 @@ namespace EMotionFX void OnAttached(AZ::EntityId targetId) override; void OnDetached(AZ::EntityId targetId) override; - // ActorNotificationBus::Handler - void OnActorReady(Actor* actor) override; - void CheckActorCreation(); void BuildGameEntity(AZ::Entity* gameEntity) override; From f39460e617d56358c83c8227203b83f547d386e5 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:08:51 -0700 Subject: [PATCH 093/153] Fix rare re-entrancy issue with CCryEditApp::IdleProcessing (#1134) This issue manifested in a crash in rare circumstances when the Editor lost and gained focus while a modal dialog was active. After investigation, it was discovered that native event processing can lead to IdleProcessing being called again from the main thread while idle processing is still happening. As this is unintentional and generally undesirable, we now guard against this within the IdleProcessing method. --- Code/Sandbox/Editor/CryEdit.cpp | 8 ++++++++ Code/Sandbox/Editor/CryEdit.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index c723e6049a..a972a4bd9b 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -2281,6 +2281,14 @@ int CCryEditApp::IdleProcessing(bool bBackgroundUpdate) return 0; } + // Ensure we don't get called re-entrantly + // This can occur when a nested Qt event loop fires (e.g. by way of a modal dialog calling exec) + if (m_idleProcessingRunning) + { + return 0; + } + QScopedValueRollback guard(m_idleProcessingRunning, true); + //////////////////////////////////////////////////////////////////////// // Call the update function of the engine //////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/CryEdit.h b/Code/Sandbox/Editor/CryEdit.h index dc4f015faf..e37fb53561 100644 --- a/Code/Sandbox/Editor/CryEdit.h +++ b/Code/Sandbox/Editor/CryEdit.h @@ -335,6 +335,8 @@ private: // If this flag is set, the next OnIdle() will update, even if the app is in the background, and then // this flag will be reset. bool m_bForceProcessIdle = false; + // This is set while IdleProcessing is running to prevent re-entrancy + bool m_idleProcessingRunning = false; // Keep the editor alive, even if no focus is set bool m_bKeepEditorActive = false; // Currently creating a new level From 34449e2fc9085e2cf5d3a7e2836479f4977d65b7 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:09:04 -0700 Subject: [PATCH 094/153] Guard GridComponent against arbitrarily high grid sizes (#1135) Also do bounds checking at runtime in the controller for safety. --- .../Code/Source/Grid/EditorGridComponent.cpp | 7 ++++--- .../Code/Source/Grid/GridComponentController.cpp | 6 +++--- .../Code/Source/Grid/GridComponentController.h | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp index f500bdd6e2..81fc3aa170 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/EditorGridComponent.cpp @@ -54,13 +54,14 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_gridSize, "Grid Size", "Grid width and depth") - ->Attribute(AZ::Edit::Attributes::Min, 0.0f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinGridSize) + ->Attribute(AZ::Edit::Attributes::Max, GridComponentController::MaxGridSize) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_primarySpacing, "Primary Grid Spacing", "Amount of space between grid lines") - ->Attribute(AZ::Edit::Attributes::Min, 0.01f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_secondarySpacing, "Secondary Grid Spacing", "Amount of space between sub-grid lines") - ->Attribute(AZ::Edit::Attributes::Min, 0.01f) + ->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing) ->Attribute(AZ::Edit::Attributes::Suffix, " m") ->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_axisColor, "Axis Color", "Color of the grid axis") ->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_primaryColor, "Primary Color", "Color of the primary grid lines") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index c2f9c896af..279c8d9035 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -115,7 +115,7 @@ namespace AZ void GridComponentController::SetSize(float gridSize) { - m_configuration.m_gridSize = gridSize; + m_configuration.m_gridSize = AZStd::clamp(gridSize, MinGridSize, MaxGridSize); m_dirty = true; } @@ -126,7 +126,7 @@ namespace AZ void GridComponentController::SetPrimarySpacing(float gridPrimarySpacing) { - m_configuration.m_primarySpacing = gridPrimarySpacing; + m_configuration.m_primarySpacing = AZStd::max(gridPrimarySpacing, MinSpacing); m_dirty = true; } @@ -137,7 +137,7 @@ namespace AZ void GridComponentController::SetSecondarySpacing(float gridSecondarySpacing) { - m_configuration.m_secondarySpacing = gridSecondarySpacing; + m_configuration.m_secondarySpacing = AZStd::max(gridSecondarySpacing, MinSpacing); m_dirty = true; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h index afba6d8327..ad603f11e1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.h @@ -46,6 +46,10 @@ namespace AZ void SetConfiguration(const GridComponentConfig& config); const GridComponentConfig& GetConfiguration() const; + static constexpr float MinGridSize = 0.0f; + static constexpr float MaxGridSize = 1000000.0f; + static constexpr float MinSpacing = 0.01f; + private: AZ_DISABLE_COPY(GridComponentController); From 30eedc1c554c8ae01e5be9d22cc372d757cd7bd0 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 3 Jun 2021 20:09:15 -0700 Subject: [PATCH 095/153] Avoid more sources of camera update re-entrancy that can lead to stack overflow (#1136) --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 3 +++ Gems/Camera/Code/Source/CameraComponentController.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 667179e3cd..0d3405f8f0 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -2887,9 +2887,12 @@ void EditorViewportWidget::UpdateCameraFromViewportContext() AZ::Matrix3x4 matrix; matrix.SetBasisAndTranslation(cameraState.m_side, cameraState.m_forward, cameraState.m_up, cameraState.m_position); auto m = AZMatrix3x4ToLYMatrix3x4(matrix); + + m_updatingCameraPosition = true; SetViewTM(m); SetFOV(cameraState.m_fovOrZoom); m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip); + m_updatingCameraPosition = false; } void EditorViewportWidget::SetAsActiveViewport() diff --git a/Gems/Camera/Code/Source/CameraComponentController.cpp b/Gems/Camera/Code/Source/CameraComponentController.cpp index cad666c1cd..78bd131002 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.cpp +++ b/Gems/Camera/Code/Source/CameraComponentController.cpp @@ -387,6 +387,11 @@ namespace Camera void CameraComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world) { + if (m_updatingTransformFromEntity) + { + return; + } + if (m_view) { CCamera& camera = m_view->GetCamera(); From 4a1d713227af339b2fbb86eb02c936cc079863c5 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 3 Jun 2021 22:36:34 -0500 Subject: [PATCH 096/153] Fix recursive attempts to open the log file in the GameLauncher (#1114) * Fix recursive attempts to open the log file in the GameLauncher The AzFramework Application has been updated to default the @user@ and @log@ aliases to the /user and /user/log folder respectively if a project isn't set. Fixed the SystemFile class to support negative offsets if Seek() as per standard seek function such as fseek Updated the CrySystem CLog class to use SystemFile instead of FileIOBase to avoid any asserts that would cause CLog::OpenFile to be recursively called infinitely * Removing unused Force Closed variable * AZ::IO::SystemFile build fixes for Unix platforms. Added a copy constructor for LUAEditorContextInterface.h to fix the LuaEditor build * Adding missing includes to the WindowsAPI and Android SystemFile headers --- Code/CryEngine/CrySystem/Log.cpp | 106 +++++++++--------- Code/CryEngine/CrySystem/Log.h | 18 ++- Code/CryEngine/CrySystem/SystemInit.cpp | 2 +- .../Framework/AzCore/AzCore/IO/SystemFile.cpp | 60 ++++++---- Code/Framework/AzCore/AzCore/IO/SystemFile.h | 21 ++-- .../Settings/SettingsRegistryMergeUtils.cpp | 2 + .../Android/AzCore/IO/SystemFile_Android.cpp | 10 +- .../Android/AzCore/IO/SystemFile_Android.h | 6 +- .../Common/Apple/AzCore/IO/SystemFile_Apple.h | 5 +- .../UnixLike/AzCore/IO/SystemFile_UnixLike.h | 6 +- .../AzCore/IO/SystemFile_UnixLikeDefault.cpp | 6 +- .../WinAPI/AzCore/IO/SystemFile_WinAPI.cpp | 8 +- .../WinAPI/AzCore/IO/SystemFile_WinAPI.h | 6 +- .../AzFramework/Application/Application.cpp | 13 ++- .../Source/LUA/LUAEditorContextInterface.h | 46 ++++++++ 15 files changed, 200 insertions(+), 115 deletions(-) diff --git a/Code/CryEngine/CrySystem/Log.cpp b/Code/CryEngine/CrySystem/Log.cpp index b8241ee865..af5170e4e5 100644 --- a/Code/CryEngine/CrySystem/Log.cpp +++ b/Code/CryEngine/CrySystem/Log.cpp @@ -26,6 +26,7 @@ #include #include +#include #ifdef WIN32 #include @@ -88,7 +89,6 @@ CLog::CLog(ISystem* pSystem) m_nMainThreadId = CryGetCurrentThreadId(); - m_logFileHandle = AZ::IO::InvalidHandle; #if defined(KEEP_LOG_FILE_OPEN) m_bFirstLine = true; #endif @@ -162,35 +162,6 @@ void CLog::RegisterConsoleVariables() REGISTER_COMMAND("log_flush", &LogFlushFile, 0, "Flush the log file"); #endif } - /* - //testbed - { - int iSave0 = m_pLogVerbosity->GetIVal(); - int iSave1 = m_pLogFileVerbosity->GetIVal(); - - for(int i=0;i<=4;++i) - { - m_pLogVerbosity->Set(i); - m_pLogFileVerbosity->Set(i); - - LogWithType(eAlways,"CLog selftest: Verbosity=%d FileVerbosity=%d",m_pLogVerbosity->GetIVal(),m_pLogFileVerbosity->GetIVal()); - LogWithType(eAlways,"--------------"); - - LogWithType(eError,"eError"); - LogWithType(eWarning,"eWarning"); - LogWithType(eMessage,"eMessage"); - LogWithType(eInput,"eInput"); - LogWithType(eInputResponse,"eInputResponse"); - - LogWarning("LogWarning()"); - LogError("LogError()"); - LogWithType(eAlways,"--------------"); - } - - m_pLogVerbosity->Set(iSave0); - m_pLogFileVerbosity->Set(iSave1); - } - */ #undef DEFAULT_VERBOSITY } @@ -210,7 +181,7 @@ CLog::~CLog() UnregisterConsoleVariables(); - CloseLogFile(true); + CloseLogFile(); } void CLog::UnregisterConsoleVariables() @@ -224,31 +195,36 @@ void CLog::UnregisterConsoleVariables() } ////////////////////////////////////////////////////////////////////////// -void CLog::CloseLogFile([[maybe_unused]] bool forceClose) +void CLog::CloseLogFile() { - if (m_logFileHandle != AZ::IO::InvalidHandle) - { - AZ::IO::FileIOBase::GetDirectInstance()->Close(m_logFileHandle); - m_logFileHandle = AZ::IO::InvalidHandle; - } + m_logFileHandle.Close(); } ////////////////////////////////////////////////////////////////////////// -AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode) +bool CLog::OpenLogFile(const char* filename, int mode) { - using namespace AZ::IO; - - AZ_Assert(m_logFileHandle == AZ::IO::InvalidHandle, "Attempt to open log file when one is already open. This would lead to a handle leak."); - - if ((!filename) || (filename[0] == 0)) + if (m_logFileHandle.IsOpen()) { - return m_logFileHandle; + // Can only AZ_Assert if a file is open, otherwise the AZ_Assert + // would eventually lead to OpenLogFile being opened up again + AZ_Assert(false, "Attempt to open log file when one is already open. This would lead to a handle leak."); + return false; + } + + if (filename == nullptr || filename[0] == '\0') + { + return false; } // it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir) - AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode(mode), m_logFileHandle); + AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance(); + if (AZ::IO::FixedMaxPath logFilePath; fileSystem->ReplaceAlias(logFilePath, filename)) + { + logFilePath = logFilePath.LexicallyNormal(); + m_logFileHandle.Open(logFilePath.c_str(), mode); + } - if (m_logFileHandle != AZ::IO::InvalidHandle) + if (m_logFileHandle.IsOpen()) { #if defined(KEEP_LOG_FILE_OPEN) m_bFirstLine = true; @@ -257,11 +233,11 @@ AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode) else { #if defined(LINUX) || defined(APPLE) - syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%s]", filename, mode); + syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%d]", filename, mode); #endif } - return m_logFileHandle; + return m_logFileHandle.IsOpen(); } ////////////////////////////////////////////////////////////////////////// @@ -1114,12 +1090,15 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[ if (logToFile) { - if (m_logFileHandle == AZ::IO::InvalidHandle) + if (!m_logFileHandle.IsOpen()) { - OpenLogFile(m_szFilename, "w+t"); + constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND + | AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE + | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY; + OpenLogFile(m_szFilename, openMode); } - if (m_logFileHandle != AZ::IO::InvalidHandle) + if (m_logFileHandle.IsOpen()) { #if defined(KEEP_LOG_FILE_OPEN) if (m_bFirstLine) @@ -1130,9 +1109,9 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[ if (bAdd) { // if adding to a prior line erase the \n at the end. - AZ::IO::FileIOBase::GetDirectInstance()->Seek(m_logFileHandle, -2, AZ::IO::SeekType::SeekFromEnd); + m_logFileHandle.Seek(-2, AZ::IO::SystemFile::SeekMode::SF_SEEK_END); } - AZ::IO::FPutS(tempString.c_str(), m_logFileHandle); + m_logFileHandle.Write(tempString.c_str(), tempString.size()); #if !defined(KEEP_LOG_FILE_OPEN) CloseLogFile(); #endif @@ -1383,6 +1362,23 @@ bool CLog::SetFileName(const char* fileNameOrAbsolutePath, bool backupLogs) CreateBackupFile(); + AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance(); + AZ::IO::FixedMaxPath newLogFilePath; + if (fileSystem->ReplaceAlias(newLogFilePath, m_szFilename)) + { + newLogFilePath = newLogFilePath.LexicallyNormal(); + } + if (m_logFileHandle.IsOpen() && newLogFilePath != m_logFileHandle.Name()) + { + constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND + | AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE + | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY; + if(AZ::IO::SystemFile newLogFile; newLogFile.Open(m_szFilename, openMode)) + { + m_logFileHandle = AZStd::move(newLogFile); + } + } + return true; } @@ -1537,9 +1533,9 @@ const char* CLog::GetModuleFilter() void CLog::FlushAndClose() { #if defined(KEEP_LOG_FILE_OPEN) - if (m_logFileHandle) + if (m_logFileHandle.IsOpen()) { - CloseLogFile(true); + CloseLogFile(); } #endif } diff --git a/Code/CryEngine/CrySystem/Log.h b/Code/CryEngine/CrySystem/Log.h index 911043871a..e19c2d19da 100644 --- a/Code/CryEngine/CrySystem/Log.h +++ b/Code/CryEngine/CrySystem/Log.h @@ -137,8 +137,8 @@ private: // ------------------------------------------------------------------- void LogStringToConsole(const char* szString, ELogType logType, bool bAdd) {} #endif // !defined(EXCLUDE_NORMAL_LOG) - AZ::IO::HandleType OpenLogFile(const char* filename, const char* mode); - void CloseLogFile(bool force = false); + bool OpenLogFile(const char* filename, int mode); + void CloseLogFile(); // will format the message into m_szTemp void FormatMessage(const char* szCommand, ...) PRINTF_PARAMS(2, 3); @@ -152,15 +152,11 @@ private: // ------------------------------------------------------------------- virtual const char* GetAssetScopeString(); #endif - ISystem* m_pSystem; // - float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update - //char m_szTemp[MAX_TEMP_LENGTH_SIZE]; // - char m_szFilename[MAX_FILENAME_SIZE]; // can be with path - mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path - AZ::IO::HandleType m_logFileHandle; - CryStackStringT m_LogMode; //mode m_pLogFile has been opened with - AZ::IO::HandleType m_errFileHandle; - int m_nErrCount; + ISystem* m_pSystem; // + float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update + char m_szFilename[MAX_FILENAME_SIZE]; // can be with path + mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path + AZ::IO::SystemFile m_logFileHandle; bool m_backupLogs; diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 4a4296bbb5..97a3bbbe54 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -1208,7 +1208,7 @@ bool CSystem::Init(const SSystemInitParams& startupParams) { assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n" - R"(This typically done by setting he "assets" field in the bootstrap.cfg for within a .setreg file)""\n" + R"(This typically done by setting the "assets" field within a .setreg file)""\n" R"(A fallback of %s will be used.)", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, assetPlatform.c_str()); diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp index 7c535d4aaf..6887d22ba7 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp @@ -30,7 +30,7 @@ namespace Platform using FileHandleType = SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode); + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode); SystemFile::SizeType Tell(FileHandleType handle, const SystemFile* systemFile); bool Eof(FileHandleType handle, const SystemFile* systemFile); AZ::u64 ModificationTime(FileHandleType handle, const SystemFile* systemFile); @@ -68,9 +68,8 @@ void SystemFile::CreatePath(const char* fileName) } SystemFile::SystemFile() + : m_handle{ AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE } { - m_fileName[0] = '\0'; - m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE; } SystemFile::~SystemFile() @@ -81,6 +80,25 @@ SystemFile::~SystemFile() } } +SystemFile::SystemFile(SystemFile&& other) + : SystemFile{} +{ + AZStd::swap(m_fileName, other.m_fileName); + AZStd::swap(m_handle, other.m_handle); +} + +SystemFile& SystemFile::operator=(SystemFile&& other) +{ + // Close the current file and take over the SystemFile handle and filename + Close(); + m_fileName = AZStd::move(other.m_fileName); + m_handle = AZStd::move(other.m_handle); + other.m_fileName = {}; + other.m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE; + + return *this; +} + bool SystemFile::Open(const char* fileName, int mode, int platformFlags) { AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Open - %s", fileName); @@ -88,42 +106,42 @@ bool SystemFile::Open(const char* fileName, int mode, int platformFlags) if (fileName) // If we reopen the file we are allowed to have NULL file name { - if (strlen(fileName) > AZ_ARRAY_SIZE(m_fileName) - 1) + if (strlen(fileName) > m_fileName.max_size()) { EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, 0); return false; } // store the filename - azsnprintf(m_fileName, AZ_ARRAY_SIZE(m_fileName), "%s", fileName); + m_fileName = fileName; } if (FileIOBus::HasHandlers()) { bool isOpen = false; bool isHandled = false; - EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName, mode, platformFlags, isOpen); + EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName.c_str(), mode, platformFlags, isOpen); if (isHandled) { return isOpen; } } - AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName); + AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName.c_str()); return PlatformOpen(mode, platformFlags); } bool SystemFile::ReOpen(int mode, int platformFlags) { - AZ_Assert(strlen(m_fileName) > 0, "Missing filename. You must call open first!"); + AZ_Assert(!m_fileName.empty(), "Missing filename. You must call open first!"); return Open(0, mode, platformFlags); } void SystemFile::Close() { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName.c_str()); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName.c_str()); if (FileIOBus::HasHandlers()) { @@ -138,9 +156,9 @@ void SystemFile::Close() PlatformClose(); } -void SystemFile::Seek(SizeType offset, SeekMode mode) +void SystemFile::Seek(SeekSizeType offset, SeekMode mode) { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName, offset); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName.c_str(), offset); if (FileIOBus::HasHandlers()) { @@ -167,15 +185,15 @@ bool SystemFile::Eof() AZ::u64 SystemFile::ModificationTime() { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName.c_str()); return Platform::ModificationTime(m_handle, this); } SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer) { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName, byteSize); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName, byteSize); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize); if (FileIOBus::HasHandlers()) { @@ -193,8 +211,8 @@ SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer) SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize) { - AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName, byteSize); - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName, byteSize); + AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize); if (FileIOBus::HasHandlers()) { @@ -212,14 +230,14 @@ SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize) void SystemFile::Flush() { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName.c_str()); Platform::Flush(m_handle, this); } SystemFile::SizeType SystemFile::Length() const { - AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName); + AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName.c_str()); return Platform::Length(m_handle, this); } @@ -379,9 +397,9 @@ namespace HasPosixEnumOption(PermissionModeFlags::Write); #undef HasPosixEnumOption -} +} + - FileDescriptorRedirector::FileDescriptorRedirector(int sourceFileDescriptor) : m_sourceFileDescriptor(sourceFileDescriptor) { diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.h b/Code/Framework/AzCore/AzCore/IO/SystemFile.h index 0ce8197b18..065aa124ca 100644 --- a/Code/Framework/AzCore/AzCore/IO/SystemFile.h +++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.h @@ -12,10 +12,11 @@ #pragma once #include -#include -#include +#include #include +#include +#include // Establish a consistent size that works across platforms. It's actually larger than this // on platforms we support, but this is a good least common denominator @@ -51,11 +52,15 @@ namespace AZ }; using SizeType = AZ::IO::Internal::SizeType; + using SeekSizeType = AZ::IO::Internal::SeekSizeType; using FileHandleType = AZ::IO::Internal::FileHandleType; SystemFile(); ~SystemFile(); + SystemFile(SystemFile&&); + SystemFile& operator=(SystemFile&&); + /** * Opens a file. * \param fileName full file name including path @@ -69,7 +74,7 @@ namespace AZ /// Closes a file, if file already close it has no effect. void Close(); /// Seek in current file. - void Seek(SizeType offset, SeekMode mode); + void Seek(SeekSizeType offset, SeekMode mode); /// Get the cursor position in the current file. SizeType Tell(); /// Is the cursor at the end of the file? @@ -87,7 +92,7 @@ namespace AZ /// Return disc offset if possible, otherwise 0 SizeType DiskOffset() const; /// Return file name or NULL if file is not open. - AZ_FORCE_INLINE const char* Name() const { return m_fileName; } + AZ_FORCE_INLINE const char* Name() const { return m_fileName.c_str(); } bool IsOpen() const; /// Return native handle to the file. @@ -124,12 +129,12 @@ namespace AZ private: static void CreatePath(const char * fileName); - + bool PlatformOpen(int mode, int platformFlags); void PlatformClose(); - - FileHandleType m_handle; - char m_fileName[AZ_MAX_PATH_LEN]; + + FileHandleType m_handle; + AZ::IO::FixedMaxPathString m_fileName; }; /** diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 2abef3f808..2d2acd9d44 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -641,6 +641,8 @@ namespace AZ::SettingsRegistryMergeUtils } else { + // Set the default ProjectUserPath to the /user directory + registry.Set(FilePathKey_ProjectUserPath, (engineRoot / "user").LexicallyNormal().Native()); AZ_TracePrintf("SettingsRegistryMergeUtils", R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n", aznumeric_cast(projectPathKey.size()), projectPathKey.data()); diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp index 2b1ebf54aa..c9950d2dfa 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp @@ -101,7 +101,7 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) createPath = (mode & SF_OPEN_CREATE_PATH) == SF_OPEN_CREATE_PATH; } - bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName); + bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName.c_str()); if (createPath) { @@ -111,19 +111,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) return false; } - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } int errorCode = 0; if (isApkFile) { AZ::u64 size = 0; - m_handle = AZ::Android::APKFileHandler::Open(m_fileName, openMode, size); + m_handle = AZ::Android::APKFileHandler::Open(m_fileName.c_str(), openMode, size); errorCode = EACCES; // general error when a file can't be opened from inside the APK } else { - m_handle = fopen(m_fileName, openMode); + m_handle = fopen(m_fileName.c_str(), openMode); errorCode = errno; } @@ -233,7 +233,7 @@ namespace Platform } } - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h index 7ccc6a076e..50255f24d4 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.h @@ -15,6 +15,9 @@ #include #include #include +#include + +#include namespace AZ { @@ -23,6 +26,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = FILE*; } @@ -37,7 +41,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h index 902dca4142..3967cafc90 100644 --- a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h +++ b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h @@ -22,9 +22,10 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = int; } - + namespace PosixInternal { enum class OpenFlags : int @@ -36,7 +37,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h index 0f55c0511b..e2d985d84e 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h @@ -13,6 +13,9 @@ #include #include +#include + +#include namespace AZ { @@ -21,6 +24,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = int; } @@ -35,7 +39,7 @@ namespace AZ #else Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. #endif - Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp index 3e40936d66..b5c3041113 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp @@ -86,9 +86,9 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) if (createPath) { - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } - m_handle = open(m_fileName, desiredAccess, permissions); + m_handle = open(m_fileName.c_str(), desiredAccess, permissions); if (m_handle == PlatformSpecificInvalidHandle) { @@ -119,7 +119,7 @@ namespace Platform { using FileHandleType = AZ::IO::SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp index e01008b1a0..fa77acb967 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp @@ -209,19 +209,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags) if (createPath) { - CreatePath(m_fileName); + CreatePath(m_fileName.c_str()); } # ifdef _UNICODE wchar_t fileNameW[AZ_MAX_PATH_LEN]; size_t numCharsConverted; m_handle = INVALID_HANDLE_VALUE; - if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0) + if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName.c_str(), AZ_ARRAY_SIZE(fileNameW) - 1) == 0) { m_handle = CreateFileW(fileNameW, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); } # else //!_UNICODE - m_handle = CreateFile(m_fileName, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); + m_handle = CreateFile(m_fileName.c_str(), dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0); # endif // !_UNICODE if (m_handle == INVALID_HANDLE_VALUE) @@ -261,7 +261,7 @@ namespace Platform { using FileHandleType = AZ::IO::SystemFile::FileHandleType; - void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode) + void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode) { if (handle != PlatformSpecificInvalidHandle) { diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h index 7f69a6b66d..09ea48c40b 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.h @@ -13,6 +13,9 @@ #include #include +#include + +#include namespace AZ { @@ -21,6 +24,7 @@ namespace AZ namespace Internal { using SizeType = AZ::u64; + using SeekSizeType = AZ::s64; using FileHandleType = void*; } @@ -31,7 +35,7 @@ namespace AZ Append = _O_APPEND, // Moves the file pointer to the end of the file before every write operation. Create = _O_CREAT, // Creates a file and opens it for writing. Has no effect if the file specified by filename exists. PermissionMode is required. Temporary = _O_TEMPORARY, // Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified. - Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. + Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists. Truncate = _O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY. // Note: The TRUNC flag destroys the contents of the specified file. diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index c65ba373f8..bc0c9e537a 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -711,8 +711,8 @@ namespace AzFramework } } - AZ::IO::FixedMaxPath projectUserPath; - if (m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) + if (AZ::IO::FixedMaxPath projectUserPath; + m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath)) { fileIoBase->SetAlias("@user@", projectUserPath.c_str()); AZ::IO::FixedMaxPath projectLogPath = projectUserPath / "log"; @@ -721,6 +721,15 @@ namespace AzFramework CreateUserCache(projectUserPath, *fileIoBase); } + else + { + AZ::IO::FixedMaxPath fallbackLogPath = GetEngineRoot(); + fallbackLogPath /= "user"; + fileIoBase->SetAlias("@user@", fallbackLogPath.c_str()); + fallbackLogPath /= "log"; + fileIoBase->SetAlias("@log@", fallbackLogPath.c_str()); + fileIoBase->CreatePath(fallbackLogPath.c_str()); + } } } diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h b/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h index 1bbfe83126..01051f42e3 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorContextInterface.h @@ -70,6 +70,52 @@ namespace LUAEditor , m_bIsModified(false) , m_bIsBeingSaved(false) , m_PresetLineAtOpen(1){} + + // Copy constructor does not copy over open file handle + DocumentInfo(const DocumentInfo& other) + : m_assetId(other.m_assetId) + , m_scriptAsset(other.m_scriptAsset) + , m_assetName(other.m_assetName) + , m_displayName(other.m_displayName) + , m_lastKnownModTime(other.m_lastKnownModTime) + , m_sourceControlInfo(other.m_sourceControlInfo) + , m_bSourceControl_Ready(other.m_bSourceControl_Ready) + , m_bSourceControl_BusyGettingStats(other.m_bSourceControl_BusyGettingStats) + , m_bSourceControl_BusyRequestingEdit(other.m_bSourceControl_BusyRequestingEdit) + , m_bSourceControl_CanWrite(other.m_bSourceControl_CanWrite) + , m_bSourceControl_CanCheckOut(other.m_bSourceControl_CanCheckOut) + , m_bDataIsLoaded(other.m_bDataIsLoaded) + , m_bDataIsWritten(other.m_bDataIsWritten) + , m_bCloseAfterSave(other.m_bCloseAfterSave) + , m_bUntitledDocument(other.m_bUntitledDocument) + , m_bIsModified(other.m_bIsModified) + , m_bIsBeingSaved(other.m_bIsBeingSaved) + , m_PresetLineAtOpen(other.m_PresetLineAtOpen) + {} + + DocumentInfo& operator=(const DocumentInfo& other) + { + m_assetId = other.m_assetId; + m_scriptAsset = other.m_scriptAsset; + m_assetName = other.m_assetName; + m_displayName = other.m_displayName; + m_lastKnownModTime = other.m_lastKnownModTime; + m_sourceControlInfo = other.m_sourceControlInfo; + m_bSourceControl_Ready = other.m_bSourceControl_Ready; + m_bSourceControl_BusyGettingStats = other.m_bSourceControl_BusyGettingStats; + m_bSourceControl_BusyRequestingEdit = other.m_bSourceControl_BusyRequestingEdit; + m_bSourceControl_CanWrite = other.m_bSourceControl_CanWrite; + m_bSourceControl_CanCheckOut = other.m_bSourceControl_CanCheckOut; + m_bDataIsLoaded = other.m_bDataIsLoaded; + m_bDataIsWritten = other.m_bDataIsWritten; + m_bCloseAfterSave = other.m_bCloseAfterSave; + m_bUntitledDocument = other.m_bUntitledDocument; + m_bIsModified = other.m_bIsModified; + m_bIsBeingSaved = other.m_bIsBeingSaved; + m_PresetLineAtOpen = other.m_PresetLineAtOpen; + + return *this; + } }; class ContextInterface From f20ae8345a398c7fd763638173f1ec76b65970a5 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 3 Jun 2021 21:58:46 -0700 Subject: [PATCH 097/153] Add Open Project folder menu item --- .../Source/ProjectButtonWidget.cpp | 30 +++++++++---------- .../Source/ProjectButtonWidget.h | 4 --- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index b1dbd984fb..ee4d48fe7f 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -11,7 +11,7 @@ */ #include - +#include #include #include @@ -81,18 +81,24 @@ namespace O3DE::ProjectManager m_projectImageLabel = new LabelButton(this); m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight); m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); vLayout->addWidget(m_projectImageLabel); m_projectImageLabel->setPixmap( QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); - QMenu* newProjectMenu = new QMenu(this); - m_editProjectAction = newProjectMenu->addAction(tr("Edit Project Settings...")); - newProjectMenu->addSeparator(); - m_copyProjectAction = newProjectMenu->addAction(tr("Duplicate")); - newProjectMenu->addSeparator(); - m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE")); - m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project")); + QMenu* menu = new QMenu(this); + menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); + menu->addSeparator(); + menu->addAction(tr("Open Project folder..."), this, [this]() + { + AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); + }); + menu->addSeparator(); + menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo.m_path); }); + menu->addSeparator(); + menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); }); + menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); }); QFrame* footer = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); @@ -104,17 +110,11 @@ namespace O3DE::ProjectManager QPushButton* projectMenuButton = new QPushButton(this); projectMenuButton->setObjectName("projectMenuButton"); - projectMenuButton->setMenu(newProjectMenu); + projectMenuButton->setMenu(menu); hLayout->addWidget(projectMenuButton); } vLayout->addWidget(footer); - - connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); - connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectInfo.m_path); }); - connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); }); - connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); }); - connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); }); } void ProjectButton::SetButtonEnabled(bool enabled) diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h index 3ac69b7603..bb61f7354b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h @@ -71,9 +71,5 @@ namespace O3DE::ProjectManager ProjectInfo m_projectInfo; LabelButton* m_projectImageLabel; - QAction* m_editProjectAction; - QAction* m_copyProjectAction; - QAction* m_removeProjectAction; - QAction* m_deleteProjectAction; }; } // namespace O3DE::ProjectManager From fefa46dd6a8c563853b2cae7d3498ad617252881 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Fri, 4 Jun 2021 02:39:25 -0700 Subject: [PATCH 098/153] Added DiffuseGlobalIlluminationFeatureProcessor and moved the DiffuseProbeGrid files to the DiffuseGlobalIllumination directory --- .../DiffuseComposite.azsl | 12 +- .../DiffuseProbeGridDownsample.azsl | 12 +- ...balIlluminationFeatureProcessorInterface.h | 40 +++++++ ...iffuseProbeGridFeatureProcessorInterface.h | 0 .../Code/Source/CommonSystemComponent.cpp | 20 ++-- ...fuseGlobalIlluminationFeatureProcessor.cpp | 113 ++++++++++++++++++ ...iffuseGlobalIlluminationFeatureProcessor.h | 52 ++++++++ .../DiffuseProbeGrid.cpp | 2 +- .../DiffuseProbeGrid.h | 2 +- .../DiffuseProbeGridBlendDistancePass.cpp | 4 +- .../DiffuseProbeGridBlendDistancePass.h | 0 .../DiffuseProbeGridBlendIrradiancePass.cpp | 4 +- .../DiffuseProbeGridBlendIrradiancePass.h | 0 .../DiffuseProbeGridBorderUpdatePass.cpp | 4 +- .../DiffuseProbeGridBorderUpdatePass.h | 0 .../DiffuseProbeGridClassificationPass.cpp | 4 +- .../DiffuseProbeGridClassificationPass.h | 3 +- .../DiffuseProbeGridFeatureProcessor.cpp | 2 +- .../DiffuseProbeGridFeatureProcessor.h | 4 +- .../DiffuseProbeGridRayTracingPass.cpp | 4 +- .../DiffuseProbeGridRayTracingPass.h | 2 +- .../DiffuseProbeGridRelocationPass.cpp | 4 +- .../DiffuseProbeGridRelocationPass.h | 3 +- .../DiffuseProbeGridRenderPass.cpp | 4 +- .../DiffuseProbeGridRenderPass.h | 0 .../DiffuseProbeGridTextureReadback.cpp | 4 +- .../DiffuseProbeGridTextureReadback.h | 2 +- .../Code/atom_feature_common_files.cmake | 42 +++---- .../atom_feature_common_public_files.cmake | 3 +- ...DiffuseGlobalIlluminationComponentConfig.h | 10 +- ...eGlobalIlluminationComponentController.cpp | 25 ++-- ...useGlobalIlluminationComponentController.h | 7 +- .../DiffuseProbeGridComponentController.h | 2 +- 33 files changed, 291 insertions(+), 99 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessorInterface.h rename Gems/Atom/Feature/Common/Code/Include/Atom/Feature/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridFeatureProcessorInterface.h (100%) create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGrid.cpp (99%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGrid.h (99%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBlendDistancePass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBlendDistancePass.h (100%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBlendIrradiancePass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBlendIrradiancePass.h (100%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBorderUpdatePass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridBorderUpdatePass.h (100%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridClassificationPass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridClassificationPass.h (97%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridFeatureProcessor.cpp (99%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridFeatureProcessor.h (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRayTracingPass.cpp (99%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRayTracingPass.h (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRelocationPass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRelocationPass.h (97%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRenderPass.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridRenderPass.h (100%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridTextureReadback.cpp (98%) rename Gems/Atom/Feature/Common/Code/Source/{DiffuseProbeGrid => DiffuseGlobalIllumination}/DiffuseProbeGridTextureReadback.h (96%) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl index b3b26c4d42..3e2fda8d5d 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseComposite.azsl @@ -37,6 +37,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass AddressV = Clamp; AddressW = Clamp; }; + + // scale multiplier of the downsampled size to the fullscreen size (e.g., 4) + uint m_imageScale; } #include @@ -148,13 +151,10 @@ float3 SampleGlobalIBL(uint sampleIndex, uint2 screenCoords, float depth, float3 PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) { uint2 screenCoords = IN.m_position.xy; - - // [GFX TODO][ATOM-6172] Add image scale PassSrg constant to the DiffuseProbeGrid downsample/upsample - const uint ImageScale = 4; - const float ImageScaleInverse = 1.0f / ImageScale; + float imageScaleInverse = 1.0f / PassSrg::m_imageScale; // compute image coords for the downsampled probe irradiance image - uint2 probeIrradianceCoords = screenCoords * ImageScaleInverse; + uint2 probeIrradianceCoords = screenCoords * imageScaleInverse; float depth = PassSrg::m_depth.Load(screenCoords, sampleIndex).r; float4 encodedNormal = PassSrg::m_normal.Load(screenCoords, sampleIndex); @@ -165,7 +165,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) float3 diffuse = float3(0.0f, 0.0f, 0.0f); if (useProbeIrradiance > 0.0f) { - float3 irradiance = SampleProbeIrradiance(sampleIndex, probeIrradianceCoords, depth, normal, albedo, ImageScale); + float3 irradiance = SampleProbeIrradiance(sampleIndex, probeIrradianceCoords, depth, normal, albedo, PassSrg::m_imageScale); diffuse = (albedo.rgb / PI) * irradiance; } else diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl index e051317567..85772c6577 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridDownsample.azsl @@ -31,6 +31,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass AddressV = Clamp; AddressW = Clamp; }; + + // scale multiplier of the downsampled size to the fullscreen size (e.g., 4) + uint m_outputImageScale; } #include @@ -56,16 +59,13 @@ struct PSOutput // Pixel Shader PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) { - // the downsample is 1/4 resolution - // [GFX TODO][ATOM-6172] Add image scale PassSrg constant to the DiffuseProbeGrid downsample/upsample - const uint ImageScale = 4; - uint2 screenCoords = IN.m_position.xy * ImageScale; + uint2 screenCoords = IN.m_position.xy * PassSrg::m_outputImageScale; float downsampledDepth = 0; float4 downsampledEncodedNormal; - for (uint y = 0; y < ImageScale; ++y) + for (uint y = 0; y < PassSrg::m_outputImageScale; ++y) { - for (uint x = 0; x < ImageScale; ++x) + for (uint x = 0; x < PassSrg::m_outputImageScale; ++x) { float depth = PassSrg::m_depth.Load(screenCoords + int2(x, y), sampleIndex).r; float4 encodedNormal = PassSrg::m_normal.Load(screenCoords + int2(x, y), sampleIndex); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessorInterface.h new file mode 100644 index 0000000000..88faac1728 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessorInterface.h @@ -0,0 +1,40 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AZ +{ + namespace Render + { + enum class DiffuseGlobalIlluminationQualityLevel : uint8_t + { + Low, + Medium, + High + }; + + //! This class provides general features and configuration for the diffuse global illumination environment, + //! which consists of DiffuseProbeGrids and the diffuse Global IBL cubemap. + class DiffuseGlobalIlluminationFeatureProcessorInterface + : public RPI::FeatureProcessor + { + public: + AZ_RTTI(AZ::Render::DiffuseProbeGridFeatureProcessorInterface, "{BD8CA35A-47C3-4FD8-932B-18495EF07527}"); + + virtual void SetQualityLevel(DiffuseGlobalIlluminationQualityLevel qualityLevel) = 0; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessorInterface.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessorInterface.h rename to Gems/Atom/Feature/Common/Code/Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessorInterface.h diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 00c55cbade..87e134477a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -91,14 +91,15 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -135,6 +136,7 @@ namespace AZ LightingPreset::Reflect(context); ModelPreset::Reflect(context); DiffuseProbeGridFeatureProcessor::Reflect(context); + DiffuseGlobalIlluminationFeatureProcessor::Reflect(context); RayTracingFeatureProcessor::Reflect(context); if (SerializeContext* serialize = azrtti_cast(context)) @@ -191,6 +193,7 @@ namespace AZ AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); + AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor(); // Add SkyBox pass @@ -285,6 +288,7 @@ namespace AZ void CommonSystemComponent::Deactivate() { AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); + AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp new file mode 100644 index 0000000000..5040665456 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp @@ -0,0 +1,113 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace Render + { + void DiffuseGlobalIlluminationFeatureProcessor::Reflect(ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext + ->Class() + ->Version(0); + } + } + + void DiffuseGlobalIlluminationFeatureProcessor::Activate() + { + EnableSceneNotification(); + } + + void DiffuseGlobalIlluminationFeatureProcessor::Deactivate() + { + DisableSceneNotification(); + } + + void DiffuseGlobalIlluminationFeatureProcessor::SetQualityLevel(DiffuseGlobalIlluminationQualityLevel qualityLevel) + { + m_qualityLevel = qualityLevel; + + UpdatePasses(); + } + + void DiffuseGlobalIlluminationFeatureProcessor::OnRenderPipelinePassesChanged([[maybe_unused]] RPI::RenderPipeline* renderPipeline) + { + UpdatePasses(); + } + + void DiffuseGlobalIlluminationFeatureProcessor::OnRenderPipelineAdded([[maybe_unused]] RPI::RenderPipelinePtr pipeline) + { + UpdatePasses(); + } + + void DiffuseGlobalIlluminationFeatureProcessor::UpdatePasses() + { + float sizeMultiplier = 0.0f; + switch (m_qualityLevel) + { + case DiffuseGlobalIlluminationQualityLevel::Low: + sizeMultiplier = 0.25f; + break; + case DiffuseGlobalIlluminationQualityLevel::Medium: + sizeMultiplier = 0.5f; + break; + case DiffuseGlobalIlluminationQualityLevel::High: + sizeMultiplier = 1.0f; + break; + default: + AZ_Assert(false, "Unknown DiffuseGlobalIlluminationQualityLevel [%d]", m_qualityLevel); + break; + } + + // update the size multiplier on the DiffuseProbeGridDownsamplePass output + AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; + RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); + const AZStd::vector& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); + for (RPI::Pass* pass : downsamplePasses) + { + for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) + { + RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; + RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; + + sizeMultipliers.m_widthMultiplier = sizeMultiplier; + sizeMultipliers.m_heightMultiplier = sizeMultiplier; + } + + // set the output scale on the PassSrg + RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); + auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); + downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + } + + // update the image scale on the DiffuseComposite pass + AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; + RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy); + const AZStd::vector& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter); + for (RPI::Pass* pass : compositePasses) + { + RPI::FullscreenTrianglePass* compositePass = static_cast(pass); + auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); + compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + } + } + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h new file mode 100644 index 0000000000..81dc1487fa --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h @@ -0,0 +1,52 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include + +namespace AZ +{ + namespace Render + { + //! This class provides general features and configuration for the diffuse global illumination environment, + //! which consists of DiffuseProbeGrids and the diffuse Global IBL cubemap. + class DiffuseGlobalIlluminationFeatureProcessor final + : public DiffuseGlobalIlluminationFeatureProcessorInterface + { + public: + AZ_RTTI(AZ::Render::DiffuseGlobalIlluminationFeatureProcessor, "{14F7DF46-AA2C-49EF-8A2C-0A7CB7390BB7}", DiffuseGlobalIlluminationFeatureProcessorInterface); + + static void Reflect(AZ::ReflectContext* context); + + DiffuseGlobalIlluminationFeatureProcessor() = default; + virtual ~DiffuseGlobalIlluminationFeatureProcessor() = default; + + void Activate() override; + void Deactivate() override; + + // DiffuseGlobalIlluminationFeatureProcessorInterface overrides + void SetQualityLevel(DiffuseGlobalIlluminationQualityLevel qualityLevel) override; + + private: + AZ_DISABLE_COPY_MOVE(DiffuseGlobalIlluminationFeatureProcessor); + + // RPI::SceneNotificationBus::Handler overrides + void OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) override; + void OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) override; + + void UpdatePasses(); + + DiffuseGlobalIlluminationQualityLevel m_qualityLevel = DiffuseGlobalIlluminationQualityLevel::Low; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp similarity index 99% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index a55d8fc78c..cfdfd9efa4 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h similarity index 99% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index ff6ad719cf..4a732ae7af 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index 2a06dacf3f..04e68136f1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -18,7 +17,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 4818018ea3..f1fe792542 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -18,7 +17,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index 8821de8a9d..a24d54d9b7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -18,7 +17,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 65f1c2dd5a..8d39e6fcc8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -22,7 +21,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h similarity index 97% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h index 677e16ac42..eef59c3753 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h @@ -12,7 +12,6 @@ #pragma once #include - #include #include #include @@ -22,7 +21,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp similarity index 99% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 060d51d1d0..ba24bcc001 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h index 19e9bf1b1d..3fb70830d0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h @@ -12,8 +12,8 @@ #pragma once -#include -#include +#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp similarity index 99% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp index 65d71b8272..c77f66645e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -25,7 +24,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h index bb35803e51..910537a2f1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index 86a26f002d..2f0ed373b9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -10,7 +10,6 @@ * */ -#include #include #include #include @@ -22,7 +21,8 @@ #include #include #include -#include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h similarity index 97% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h index 437ac2f3f5..1900f8b786 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h @@ -12,7 +12,6 @@ #pragma once #include - #include #include #include @@ -22,7 +21,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp index 4f9221a65f..f025079994 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp @@ -10,12 +10,12 @@ * */ -#include -#include #include #include #include #include +#include +#include #include namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h similarity index 100% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp similarity index 98% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.cpp rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp index bc619cc277..5465d0da33 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp @@ -10,8 +10,8 @@ * */ -#include -#include +#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h similarity index 96% rename from Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h rename to Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h index 1becd6fb3e..6f7ebb9240 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 76b71e5fae..0df5501803 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -119,26 +119,28 @@ set(FILES Source/Decals/AsyncLoadTracker.h Source/Decals/DecalTextureArrayFeatureProcessor.h Source/Decals/DecalTextureArrayFeatureProcessor.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridRayTracingPass.h - Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridBlendIrradiancePass.h - Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridBlendDistancePass.h - Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridBorderUpdatePass.h - Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridRelocationPass.h - Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridClassificationPass.h - Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridRenderPass.h - Source/DiffuseProbeGrid/DiffuseProbeGrid.cpp - Source/DiffuseProbeGrid/DiffuseProbeGrid.h - Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.cpp - Source/DiffuseProbeGrid/DiffuseProbeGridTextureReadback.h - Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.h - Source/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessor.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.h + Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp + Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h + Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.h + Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp Source/DisplayMapper/AcesOutputTransformPass.cpp Source/DisplayMapper/AcesOutputTransformLutPass.cpp Source/DisplayMapper/ApplyShaperLookupTablePass.cpp diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake index 9034859707..9f9c64dd46 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_public_files.cmake @@ -22,7 +22,8 @@ set(FILES Include/Atom/Feature/CoreLights/SimpleSpotLightFeatureProcessorInterface.h Include/Atom/Feature/CoreLights/ShadowConstants.h Include/Atom/Feature/Decals/DecalFeatureProcessorInterface.h - Include/Atom/Feature/DiffuseProbeGrid/DiffuseProbeGridFeatureProcessorInterface.h + Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessorInterface.h + Include/Atom/Feature/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessorInterface.h Include/Atom/Feature/DisplayMapper/DisplayMapperFeatureProcessorInterface.h Include/Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h index 23296967a5..fb99a99e1a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentConfig.h @@ -14,20 +14,12 @@ #include #include +#include namespace AZ { namespace Render { - enum class DiffuseGlobalIlluminationQualityLevel : uint32_t - { - Low, - Medium, - High, - - Count - }; - class DiffuseGlobalIlluminationComponentConfig final : public ComponentConfig { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp index 4c7f37bd4a..a9feb0185c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp @@ -11,11 +11,8 @@ */ #include - -//#include - +#include #include -//#include namespace AZ { @@ -55,18 +52,22 @@ namespace AZ void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId) { - m_entityId = entityId; + AZ_UNUSED(entityId); + + const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + m_featureProcessor = scene->GetFeatureProcessor(); + + OnConfigChanged(); } void DiffuseGlobalIlluminationComponentController::Deactivate() { - //m_postProcessInterface = nullptr; - m_entityId.SetInvalid(); } void DiffuseGlobalIlluminationComponentController::SetConfiguration(const DiffuseGlobalIlluminationComponentConfig& config) { m_configuration = config; + OnConfigChanged(); } @@ -77,15 +78,7 @@ namespace AZ void DiffuseGlobalIlluminationComponentController::OnConfigChanged() { - // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. - //const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - //DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor(); - //DisplayMapperConfigurationDescriptor desc; - //desc.m_operationType = m_configuration.m_displayMapperOperation; - //desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled; - //desc.m_ldrColorGradingLut = m_configuration.m_ldrColorGradingLut; - //desc.m_acesParameterOverrides = m_configuration.m_acesParameterOverrides; - //fp->RegisterDisplayMapperConfiguration(desc); + m_featureProcessor->SetQualityLevel(m_configuration.m_qualityLevel); } } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h index 8700e1ffb5..81da772129 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.h @@ -14,12 +14,9 @@ #include #include - +#include #include -//#include -//#include - namespace AZ { namespace Render @@ -49,7 +46,7 @@ namespace AZ void OnConfigChanged(); DiffuseGlobalIlluminationComponentConfig m_configuration; - EntityId m_entityId; + DiffuseGlobalIlluminationFeatureProcessorInterface* m_featureProcessor = nullptr; }; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h index ef606d2170..51a17cb2cf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include From 05e20803a89253bd8f7ba6ef507242e08d833d72 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:32:06 +0100 Subject: [PATCH 099/153] First pass for getting things ready for grid snap button (#1118) * first pass of change to simplify snapping for snap-to-grid button and fix snapping bug caused by non-uniform scale --- .../AzManipulatorTestFrameworkUtils.h | 25 ++-- .../AzManipulatorTestFrameworkUtils.cpp | 58 +++++---- .../Tests/GridSnappingTest.cpp | 120 +++++++++++++----- .../Manipulators/BaseManipulator.cpp | 5 + .../Manipulators/EditorVertexSelection.cpp | 27 ++-- .../Manipulators/LinearManipulator.cpp | 70 ++++------ .../Manipulators/LinearManipulator.h | 12 +- .../Manipulators/ManipulatorSnapping.cpp | 36 ++++-- .../Manipulators/ManipulatorSnapping.h | 22 ++-- .../Manipulators/MultiLinearManipulator.cpp | 28 ++-- .../Manipulators/MultiLinearManipulator.h | 2 - .../Manipulators/PlanarManipulator.cpp | 50 +++----- .../Manipulators/PlanarManipulator.h | 13 +- .../EditorNonUniformScaleComponentMode.cpp | 48 ++++--- .../EditorTransformComponentSelection.cpp | 39 ++---- 15 files changed, 295 insertions(+), 260 deletions(-) diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h index dcddf1e5a5..f1c32e4d8d 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h @@ -12,17 +12,22 @@ #pragma once -#include -#include #include +#include +#include +#include namespace AzManipulatorTestFramework { - //! Create a linear manipulator with a unit sphere bounds. + //! Create a linear manipulator with a unit sphere bound. AZStd::shared_ptr CreateLinearManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, - const AZ::Vector3& position = AZ::Vector3::CreateZero(), - const float radius = 1.0f); + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + float radius = 1.0f); + + //! Create a planar manipulator with a unit sphere bound. + AZStd::shared_ptr CreatePlanarManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + float radius = 1.0f); //! Create a mouse pick from the specified ray and screen point. AzToolsFramework::ViewportInteraction::MousePick CreateMousePick( @@ -34,14 +39,12 @@ namespace AzManipulatorTestFramework //! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers. AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction( - const AzToolsFramework::ViewportInteraction::MousePick& mousePick, - AzToolsFramework::ViewportInteraction::MouseButtons buttons, + const AzToolsFramework::ViewportInteraction::MousePick& mousePick, AzToolsFramework::ViewportInteraction::MouseButtons buttons, AzToolsFramework::ViewportInteraction::InteractionId interactionId, AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers); //! Create a mouse buttons from the specified mouse button. - AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons( - AzToolsFramework::ViewportInteraction::MouseButton button); + AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton button); //! Create a mouse interaction event from the specified interaction and event. AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent( @@ -61,5 +64,5 @@ namespace AzManipulatorTestFramework AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState); //! Default viewport size (1080p) in 16:9 aspect ratio. - const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f); + inline const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f); } // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp index b255fcae73..985c21cf8e 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace AzManipulatorTestFramework @@ -28,22 +27,21 @@ namespace AzManipulatorTestFramework using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent; using MousePick = AzToolsFramework::ViewportInteraction::MousePick; - AZStd::shared_ptr CreateLinearManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, - const AZ::Vector3& position, - const float radius) + // create a default sphere view for a manipulator for simple intersection + template + void SetupManipulatorView( + AZStd::shared_ptr manipulator, const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, + const AZ::Vector3& position, const float radius) { - auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity()); - manipulator->SetLocalPosition(position); - // unit sphere view auto sphereView = AzToolsFramework::CreateManipulatorViewSphere( AZ::Colors::Red, radius, - [](const MouseInteraction& /*mouseInteraction*/, const bool /*mouseOver*/, - const AZ::Color& defaultColor) - { - return defaultColor; - }, true); + []([[maybe_unused]] const MouseInteraction& mouseInteraction, [[maybe_unused]] const bool mouseOver, + const AZ::Color& defaultColor) + { + return defaultColor; + }, + true); // unit sphere bound AzToolsFramework::Picking::BoundShapeSphere sphereBound; @@ -62,6 +60,26 @@ namespace AzManipulatorTestFramework // this would occur internally when the manipulator is drawn but we must do manually here to ensure that the // bounds will always be valid upon instantiation view->RefreshBound(manipulatorManagerId, manipulator->GetManipulatorId(), sphereBound); + } + + AZStd::shared_ptr CreateLinearManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius) + { + auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity()); + manipulator->SetLocalPosition(position); + + SetupManipulatorView(manipulator, manipulatorManagerId, position, radius); + + return manipulator; + } + + AZStd::shared_ptr CreatePlanarManipulator( + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius) + { + auto manipulator = AzToolsFramework::PlanarManipulator::MakeShared(AZ::Transform::CreateIdentity()); + manipulator->SetLocalPosition(position); + + SetupManipulatorView(manipulator, manipulatorManagerId, position, radius); return manipulator; } @@ -104,8 +122,7 @@ namespace AzManipulatorTestFramework return buttons; } - MouseInteractionEvent CreateMouseInteractionEvent( - const MouseInteraction& mouseInteraction, MouseEvent event) + MouseInteractionEvent CreateMouseInteractionEvent(const MouseInteraction& mouseInteraction, MouseEvent event) { return MouseInteractionEvent(mouseInteraction, event); } @@ -114,8 +131,7 @@ namespace AzManipulatorTestFramework { AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event( AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, - event); + &AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, event); } AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState) @@ -133,9 +149,7 @@ namespace AzManipulatorTestFramework AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState) { - return { - aznumeric_cast(cameraState.m_viewportSize.GetX() / 2.f), - aznumeric_cast(cameraState.m_viewportSize.GetY() / 2.f) - }; + return { aznumeric_cast(cameraState.m_viewportSize.GetX() / 2.f), + aznumeric_cast(cameraState.m_viewportSize.GetY() / 2.f) }; } -} // namespace UnitTest +} // namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp index e6468c1ebb..d6006ba74f 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp @@ -10,52 +10,55 @@ * */ +#include "AzManipulatorTestFrameworkTestFixtures.h" + #include #include #include -#include "AzManipulatorTestFrameworkTestFixtures.h" -#include -#include -#include #include +#include +#include +#include +#include +#include #include +#include namespace UnitTest { - class GridSnappingFixture - : public ToolsApplicationFixture + class GridSnappingFixture : public ToolsApplicationFixture { public: GridSnappingFixture() : m_viewportManipulatorInteraction(AZStd::make_unique()) - , m_actionDispatcher(AZStd::make_unique(*m_viewportManipulatorInteraction)) - , m_linearManipulator( - AzManipulatorTestFramework::CreateLinearManipulator( - m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), - /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), - /*radius=*/m_boundsRadius)) - {} + , m_actionDispatcher( + AZStd::make_unique(*m_viewportManipulatorInteraction)) + { + } protected: void SetUpEditorFixtureImpl() override { - m_cameraState = AzFramework::CreateIdentityDefaultCamera( - AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); + m_cameraState = + AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } public: - const float m_boundsRadius = 1.0f; AZStd::unique_ptr m_viewportManipulatorInteraction; AZStd::unique_ptr m_actionDispatcher; - AZStd::shared_ptr m_linearManipulator; AzFramework::CameraState m_cameraState; }; TEST_F(GridSnappingFixture, MouseDownWithSnappingEnabledSnapsToClosestGridSize) { + AZStd::shared_ptr linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), + /*radius=*/m_boundsRadius)); + // the initial starting position of the manipulator (in front of the camera) - const auto initialPositionWorld = m_linearManipulator->GetLocalPosition(); + const auto initialPositionWorld = linearManipulator->GetLocalPosition(); // where the manipulator should end up (in front and to the left of the camera) const auto finalPositionWorld = AZ::Vector3(-10.0f, 50.0f, 0.0f); // perspective scale factor for manipulator distance to camera @@ -66,21 +69,18 @@ namespace UnitTest // adjusted final world position taking into account the manipulator position relative to the camera const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound); // calculate the position in screen space of the initial position of the manipulator - const auto initialPositionScreen = - AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); + const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); // calculate the position in screen space of the final position of the manipulator const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState); // callback to update the manipulator's current position - m_linearManipulator->InstallMouseMoveCallback( - [this](const AzToolsFramework::LinearManipulator::Action& action) - { - auto pos = action.LocalPosition(); - m_linearManipulator->SetLocalPosition(pos); - }); + linearManipulator->InstallMouseMoveCallback( + [this, linearManipulator](const AzToolsFramework::LinearManipulator::Action& action) + { + linearManipulator->SetLocalPosition(action.LocalPosition()); + }); - m_actionDispatcher - ->EnableSnapToGrid() + m_actionDispatcher->EnableSnapToGrid() ->GridSize(5.0f) ->CameraState(m_cameraState) ->MousePosition(initialPositionScreen) @@ -89,7 +89,67 @@ namespace UnitTest ->MousePosition(finalPositionScreen) ->MouseLButtonUp() ->ExpectManipulatorNotBeingInteracted() - ->ExpectTrue(m_linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f)) - ; + ->ExpectTrue(linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f)); + } + + template + void ValidateManipulatorSnappingBehavior( + AZStd::shared_ptr manipulator, AzManipulatorTestFramework::ImmediateModeActionDispatcher* actionDispatcher, + const AzFramework::CameraState& cameraState) + { + manipulator->SetLocalOrientation(AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(180.0f, 0.0f, 135.0f))); + + // the initial starting position of the manipulator (in front of the camera) + const auto initialPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.15f); + // where the manipulator should end up (unmoved) + const auto finalPositionWorld = manipulator->GetLocalPosition(); + // where we should move the mouse to + const auto attemptPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.35f); + // calculate the position in screen space of the initial position of the manipulator + const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, cameraState); + // calculate the position in screen space of the final position of the manipulator + const auto attemptPositionScreen = AzFramework::WorldToScreen(attemptPositionWorld, cameraState); + + // callback to update the manipulator's current position + manipulator->InstallMouseMoveCallback( + [manipulator](const typename Manipulator::Action& action) + { + manipulator->SetLocalPosition(action.LocalPosition()); + }); + + actionDispatcher->EnableSnapToGrid() + ->GridSize(1.0f) + ->CameraState(cameraState) + ->MousePosition(initialPositionScreen) + ->MouseLButtonDown() + ->ExpectManipulatorBeingInteracted() + ->MousePosition(attemptPositionScreen) + ->MouseLButtonUp() + ->ExpectManipulatorNotBeingInteracted() + ->ExpectThat(manipulator->GetLocalPosition(), IsCloseTolerance(finalPositionWorld, 0.01f)); + } + + TEST_F(GridSnappingFixture, MouseDownAndMoveLinearManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize) + { + AZStd::shared_ptr linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f), + /*radius=*/m_boundsRadius)); + + linearManipulator->SetAxis(AZ::Vector3::CreateAxisY()); + + ValidateManipulatorSnappingBehavior(linearManipulator, m_actionDispatcher.get(), m_cameraState); + } + + TEST_F(GridSnappingFixture, MouseDownAndMovePlanarManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize) + { + AZStd::shared_ptr planarManipulator(AzManipulatorTestFramework::CreatePlanarManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f), + /*radius=*/m_boundsRadius)); + + planarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + + ValidateManipulatorSnappingBehavior(planarManipulator, m_actionDispatcher.get(), m_cameraState); } } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp index e7235f0f82..955d10d3bd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp @@ -433,6 +433,11 @@ namespace AzToolsFramework return m_manipulatorSpaceWithLocalTransform.GetSpace(); } + const AZ::Vector3& Manipulators::GetNonUniformScale() const + { + return m_manipulatorSpaceWithLocalTransform.GetNonUniformScale(); + } + void Manipulators::SetSpace(const AZ::Transform& worldFromLocal) { m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp index 4d10a4c171..55a8464ba6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp @@ -192,8 +192,7 @@ namespace AzToolsFramework /// for each vertex associated with the translation manipulator to use with offset calculations when updating. template void InitializeVertexLookup( - IndexedTranslationManipulator& translationManipulator, - const AZ::EntityId entityId, const AZ::Vector3& snapOffset) + IndexedTranslationManipulator& translationManipulator, const AZ::EntityId entityId) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -202,7 +201,7 @@ namespace AzToolsFramework AZ::FixedVerticesRequestBus::Bind(fixedVertices, entityId); translationManipulator.Process( - [snapOffset, fixedVertices] + [fixedVertices] (typename IndexedTranslationManipulator::VertexLookup& vertexLookup) { Vertex vertex; @@ -213,7 +212,7 @@ namespace AzToolsFramework if (found) { - vertexLookup.m_start = vertex + AZ::AdaptVertexIn(snapOffset); + vertexLookup.m_start = vertex; vertexLookup.m_offset = Vertex::CreateZero(); } }); @@ -250,10 +249,10 @@ namespace AzToolsFramework // linear manipulator callbacks m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseDownCallback( - [this](const LinearManipulator::Action& action) + [this]([[maybe_unused]] const LinearManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_positionSnapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseMoveCallback( @@ -264,17 +263,17 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseUpCallback( - [this](const LinearManipulator::Action& /*action*/) + [this]([[maybe_unused]] const LinearManipulator::Action& action) { EndBatchMovement(); }); // planar manipulator callbacks m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseDownCallback( - [this](const PlanarManipulator::Action& action) + [this]([[maybe_unused]] const PlanarManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseMoveCallback( @@ -285,17 +284,17 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseUpCallback( - [this](const PlanarManipulator::Action& /*action*/) + [this]([[maybe_unused]] const PlanarManipulator::Action& action) { EndBatchMovement(); }); // surface manipulator callbacks m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseDownCallback( - [this](const SurfaceManipulator::Action& action) + [this]([[maybe_unused]] const SurfaceManipulator::Action& action) { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseMoveCallback( @@ -306,7 +305,7 @@ namespace AzToolsFramework }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseUpCallback( - [this](const SurfaceManipulator::Action& /*action*/) + [this]([[maybe_unused]] const SurfaceManipulator::Action& action) { EndBatchMovement(); }); @@ -893,7 +892,7 @@ namespace AzToolsFramework { BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId(), AZ::Vector3::CreateZero()); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); // note: AdaptVertexIn/Out is to ensure we clamp the vertex local Z position to 0 if // dealing with Vector2s when setting the position of the manipulator. const AZ::Vector3 localOffset = diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp index aa84fc5752..34ae28bd13 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp @@ -23,8 +23,8 @@ namespace AzToolsFramework { LinearManipulator::Starter CalculateLinearManipulationDataStart( const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction, - const float intersectionDistance, const AzFramework::CameraState& cameraState) + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance, + const AzFramework::CameraState& cameraState) { const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( @@ -50,28 +50,9 @@ namespace AzToolsFramework manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, startTransition.m_localNormal, start.m_localHitPosition); - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; - - // calculate position amount to snap, to align with grid - const AZ::Vector3 positionSnapOffset = snapping && !gridSnapAction.m_localSnapping - ? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip) - : AZ::Vector3::CreateZero(); - - const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale()); - const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform); - // calculate scale amount to snap, to align to round scale value - const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping - ? localRotation.GetInverseFull().TransformVector(CalculateSnappedOffset( - localRotation.TransformVector(localScale), axis, gridSize * scaleRecip)) - : AZ::Vector3::CreateZero(); - start.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; - start.m_positionSnapOffset = positionSnapOffset; - start.m_scaleSnapOffset = scaleSnapOffset; - start.m_localPosition = localTransform.GetTranslation() + positionSnapOffset; - start.m_localScale = localScale + scaleSnapOffset; + start.m_localPosition = localTransform.GetTranslation(); + start.m_localScale = AZ::Vector3(localTransform.GetUniformScale());; start.m_localAxis = axis; // sign to determine which side of the linear axis we pressed // (useful to know when the visual axis flips to face the camera) @@ -87,7 +68,7 @@ namespace AzToolsFramework LinearManipulator::Action CalculateLinearManipulationDataAction( const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction) + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) { const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( @@ -108,31 +89,34 @@ namespace AzToolsFramework GetCameraState(interaction.m_interactionId.m_viewportId)); const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis); - // The local positions have been transformed to the reference frame of the object being manipulated. But they appear in the world - // with non-uniform scale applied, and the object being manipulated will want to work with unscaled deltas, so we need to divide by - // the non-uniform scale here. + // the local positions have been transformed to the reference frame of the object being manipulated, but they appear in the world + // with non-uniform scale applied, the object being manipulated will want to work with unscaled deltas, so we need to divide by + // the non-uniform scale here const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition) / nonUniformScale; const AZ::Vector3 unsnappedOffset = axis * axis.Dot(hitDelta); - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal * axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal); - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; + const float scaleRecip = + manipulatorInteraction.m_scaleReciprocal * fixed.m_axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal); + const float gridSize = gridSnapParams.m_gridSize; + const bool snapping = gridSnapParams.m_gridSnap; LinearManipulator::Action action; action.m_fixed = fixed; action.m_start = start; action.m_current.m_localPositionOffset = snapping - ? unsnappedOffset + CalculateSnappedOffset(unsnappedOffset, axis, gridSize * scaleRecip) + ? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip) : unsnappedOffset; action.m_current.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; action.m_viewportId = interaction.m_interactionId.m_viewportId; const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform); - const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale); + const AZ::Vector3 scaledUnsnappedOffset = + unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale); + // how much to adjust the scale based on movement const AZ::Quaternion invLocalRotation = localRotation.GetInverseFull(); action.m_current.m_localScaleOffset = snapping - ? invLocalRotation.TransformVector((scaledUnsnappedOffset + CalculateSnappedOffset(scaledUnsnappedOffset, axis, gridSize * scaleRecip))) + ? invLocalRotation.TransformVector(CalculateSnappedAmount(scaledUnsnappedOffset, axis, gridSize * scaleRecip)) : invLocalRotation.TransformVector(scaledUnsnappedOffset); // record what modifier keys are held during this action @@ -171,19 +155,18 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_starter = CalculateLinearManipulationDataStart( - m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance, + m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance, GetCameraState(interaction.m_interactionId.m_viewportId)); if (m_onLeftMouseDownCallback) { + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); + m_onLeftMouseDownCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction)); } } @@ -195,8 +178,8 @@ namespace AzToolsFramework // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_onMouseMoveCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, + interaction)); } } @@ -208,8 +191,7 @@ namespace AzToolsFramework // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction)); } } @@ -232,8 +214,8 @@ namespace AzToolsFramework GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); const auto action = CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, + mouseInteraction); // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h index 576c543dce..c3d43a2535 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h @@ -20,7 +20,7 @@ namespace AzToolsFramework { - struct GridSnapAction; + struct GridSnapParameters; /// LinearManipulator serves as a visual tool for users to modify values /// in one dimension on an axis defined in 3D space. @@ -68,8 +68,6 @@ namespace AzToolsFramework AZ::Vector3 m_localScale; ///< The current scale of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. AZ::Vector3 m_localAxis; ///< The axis in the local space of the manipulator itself. - AZ::Vector3 m_positionSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. - AZ::Vector3 m_scaleSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to round scale increments. float m_sign; ///< Used to determine which side of the axis we clicked on in case it's flipped to face the camera. AzFramework::ScreenPoint m_screenPosition; ///< The initial position in screen space of the manipulator. }; @@ -91,7 +89,7 @@ namespace AzToolsFramework ViewportInteraction::KeyboardModifiers m_modifiers; int m_viewportId; ///< The id of the viewport this manipulator is being used in. AZ::Vector3 LocalScale() const { return m_start.m_localScale + m_current.m_localScaleOffset; } - AZ::Vector3 LocalScaleOffset() const { return m_start.m_scaleSnapOffset + m_current.m_localScaleOffset; } + AZ::Vector3 LocalScaleOffset() const { return m_current.m_localScaleOffset; } AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; } AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; } AZ::Vector2 ScreenOffset() const @@ -162,11 +160,11 @@ namespace AzToolsFramework LinearManipulator::Starter CalculateLinearManipulationDataStart( const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction, - float intersectionDistance, const AzFramework::CameraState& cameraState); + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance, + const AzFramework::CameraState& cameraState); LinearManipulator::Action CalculateLinearManipulationDataAction( const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction); + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp index 015ea8a3e3..8a6398d025 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp @@ -42,12 +42,6 @@ namespace AzToolsFramework { } - GridSnapAction::GridSnapAction(const GridSnapParameters& gridSnapParameters, const bool localSnapping) - : m_gridSnapParams(gridSnapParameters) - , m_localSnapping(localSnapping) - { - } - ManipulatorInteraction BuildManipulatorInteraction( const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection) @@ -57,19 +51,39 @@ namespace AzToolsFramework return {localFromWorldUniform.TransformPoint(worldRayOrigin), TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection), - ScaleReciprocal(worldFromLocalUniform), - NonUniformScaleReciprocal(nonUniformScale)}; + NonUniformScaleReciprocal(nonUniformScale), + ScaleReciprocal(worldFromLocalUniform)}; } - AZ::Vector3 CalculateSnappedOffset( - const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + struct SnapAdjustment + { + float m_existingSnapDistance; //!< How far to snap up or down to align to the grid. + float m_nextSnapDistance; //!< The snap increment (will return full signed value (grid size) when distance + //!< moved is greater than half of the grid size in either direction). + }; + + static SnapAdjustment CalculateSnapDistance(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) { // calculate total distance along axis const float axisDistance = axis.Dot(unsnappedPosition); // round to nearest step size const float snappedAxisDistance = floorf((axisDistance / size) + 0.5f) * size; + + return { axisDistance, snappedAxisDistance }; + } + + AZ::Vector3 CalculateSnappedOffset(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + { + const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size); // return offset along axis to snap to step size - return axis * (snappedAxisDistance - axisDistance); + return axis * (snapAdjustment.m_nextSnapDistance - snapAdjustment.m_existingSnapDistance); + } + + AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size) + { + const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size); + // return offset along axis to snap to step size + return axis * snapAdjustment.m_nextSnapDistance; } AZ::Vector3 CalculateSnappedTerrainPosition( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h index e6c70079df..11860780c7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h @@ -31,24 +31,15 @@ namespace AzToolsFramework float m_gridSize; }; - /// Structure to encapsulate the current grid snapping state. - struct GridSnapAction - { - GridSnapAction(const GridSnapParameters& gridSnapParameters, bool localSnapping); - - GridSnapParameters m_gridSnapParams; - bool m_localSnapping; - }; - /// Structure to hold transformed incoming viewport interaction from world space to manipulator space. struct ManipulatorInteraction { AZ::Vector3 m_localRayOrigin; ///< The ray origin (start) in the reference from of the manipulator. AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator. - float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the - ///< ray from world space to local space. AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied ///< separately from the transform. + float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the + ///< ray from world space to local space. }; /// Build a ManipulatorInteraction structure from the incoming viewport interaction. @@ -56,11 +47,16 @@ namespace AzToolsFramework const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection); - /// Calculate the offset along an axis to adjust a position - /// to stay snapped to a given grid size. + /// Calculate the offset along an axis to adjust a position to stay snapped to a given grid size. + /// @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2, + /// 0.7 snaps to 1.0 -> delta 0.3). AZ::Vector3 CalculateSnappedOffset( const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + /// Return the amount to snap from the starting position given the current grid size. + /// @note A movement of more than half size (in either direction) will cause a snap by size. + AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + /// For a given point on the terrain, calculate the closest xy position snapped to the grid /// (z position is aligned to terrain height, not snapped to z grid) AZ::Vector3 CalculateSnappedTerrainPosition( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp index 566de9a8a6..83c4c28e9a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp @@ -59,17 +59,16 @@ namespace AzToolsFramework const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const AZStd::vector& fixedAxes, - const AZStd::vector& starterStates, const GridSnapAction& gridSnapAction) + const AZStd::vector& starterStates, const GridSnapParameters& gridSnapParams) { MultiLinearManipulator::Action action; action.m_viewportId = interaction.m_interactionId.m_viewportId; // build up action state for each axis for (size_t fixedIndex = 0; fixedIndex < fixedAxes.size(); ++fixedIndex) { - action.m_actions.push_back( - CalculateLinearManipulationDataAction( - fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, - gridSnapAction, interaction)); + action.m_actions.push_back(CalculateLinearManipulationDataAction( + fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, gridSnapParams, + interaction)); } return action; @@ -79,8 +78,6 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); const AzFramework::CameraState cameraState = GetCameraState(interaction.m_interactionId.m_viewportId); // build up initial start state for each axis @@ -88,20 +85,19 @@ namespace AzToolsFramework { // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap const auto linearStart = CalculateLinearManipulationDataStart( - fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, - rayIntersectionDistance, cameraState); + fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance, + cameraState); m_starters.push_back(linearStart); } if (m_onLeftMouseDownCallback) { - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); // pass action containing all linear actions for each axis to handler m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); } } @@ -111,11 +107,9 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); - m_onMouseMoveCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); } } @@ -125,11 +119,9 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()); - m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction( worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapAction)); + interaction, m_fixedAxes, m_starters, gridSnapParams)); m_starters.clear(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h index 4a99435008..8e31e02605 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h @@ -20,8 +20,6 @@ namespace AzToolsFramework { - struct GridSnapAction; - //! MultiLinearManipulator serves as a visual tool for users to modify values //! in one or more dimensions on axes defined in 3D space. class MultiLinearManipulator diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp index abd5414ce3..6eb96f081c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp @@ -22,8 +22,7 @@ namespace AzToolsFramework { PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, + const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance) { const ManipulatorInteraction manipulatorInteraction = @@ -31,8 +30,6 @@ namespace AzToolsFramework worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal); - const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1); - const AZ::Vector3 axis2 = TransformDirectionNoScaling(localTransform, fixed.m_axis2); // initial intersect point const AZ::Vector3 localIntersectionPoint = @@ -43,25 +40,14 @@ namespace AzToolsFramework manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, normal, startInternal.m_localHitPosition); - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; - - // calculate amount to snap to align with grid - const AZ::Vector3 snapOffset = snapping && !gridSnapAction.m_localSnapping - ? CalculateSnappedOffset(localTransform.GetTranslation(), axis1, gridSize * scaleRecip) + - CalculateSnappedOffset(localTransform.GetTranslation(), axis2, gridSize * scaleRecip) - : AZ::Vector3::CreateZero(); - - startInternal.m_snapOffset = snapOffset; - startInternal.m_localPosition = localTransform.GetTranslation() + snapOffset; + startInternal.m_localPosition = localTransform.GetTranslation(); return startInternal; } PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, + const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) { const ManipulatorInteraction manipulatorInteraction = @@ -88,20 +74,18 @@ namespace AzToolsFramework const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition) / nonUniformScale; const AZ::Vector3 unsnappedOffset = axis1.Dot(hitDelta) * axis1 + axis2.Dot(hitDelta) * axis2; - const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; const AZ::Vector3 nonUniformScaleRecip = manipulatorInteraction.m_nonUniformScaleReciprocal; - const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize; - const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap; + const float scaleRecip = manipulatorInteraction.m_scaleReciprocal; + const float gridSize = gridSnapParams.m_gridSize; + const bool snapping = gridSnapParams.m_gridSnap; Action action; action.m_fixed = fixed; action.m_start.m_localPosition = startInternal.m_localPosition; - action.m_start.m_snapOffset = startInternal.m_snapOffset; action.m_start.m_localHitPosition = startInternal.m_localHitPosition; action.m_current.m_localOffset = snapping - ? unsnappedOffset + - CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis1)) + - CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis2)) + ? CalculateSnappedAmount(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis1)) + + CalculateSnappedAmount(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis2)) : unsnappedOffset; // record what modifier keys are held during this action @@ -141,18 +125,17 @@ namespace AzToolsFramework { const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); - const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); - m_startInternal = CalculateManipulationDataStart( m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance); if (m_onLeftMouseDownCallback) { + const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); + m_onLeftMouseDownCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + gridSnapParams, interaction)); } } @@ -164,8 +147,7 @@ namespace AzToolsFramework m_onMouseMoveCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction)); } } @@ -177,8 +159,7 @@ namespace AzToolsFramework m_onLeftMouseUpCallback(CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction)); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction)); } } @@ -195,8 +176,7 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); const auto action = CalculateManipulationDataAction( m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(), - TransformNormalizedScale(GetLocalTransform()), - GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction); + TransformNormalizedScale(GetLocalTransform()), gridSnapParams, mouseInteraction); // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h index 7a3b2a18a9..154ed4c7d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h @@ -21,7 +21,7 @@ namespace AzToolsFramework { class ManipulatorView; - struct GridSnapAction; + struct GridSnapParameters; /// PlanarManipulator serves as a visual tool for users to modify values /// in two dimension in a plane defined two non-collinear axes in 3D space. @@ -58,7 +58,6 @@ namespace AzToolsFramework { AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. }; /// The state of the manipulator during an interaction. @@ -120,7 +119,6 @@ namespace AzToolsFramework { AZ::Vector3 m_localPosition; ///< The starting position of the manipulator in local space. AZ::Vector3 m_localHitPosition; ///< The intersection point in world space between the ray and the manipulator when the mouse down event happens. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. }; Fixed m_fixed; @@ -134,12 +132,11 @@ namespace AzToolsFramework static StartInternal CalculateManipulationDataStart( const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, - const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance); + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance); static Action CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction); + const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, + const ViewportInteraction::MouseInteraction& interaction); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp index 497bcf15d7..51c5406812 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp @@ -37,13 +37,13 @@ namespace AzToolsFramework axisLength, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor); - auto mouseDownCallback = [this](const LinearManipulator::Action& action) { + auto mouseDownCallback = [this]([[maybe_unused]] const LinearManipulator::Action& action) + { AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne(); - AZ::NonUniformScaleRequestBus::EventResult( nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale); - m_initialScale = nonUniformScale + action.m_start.m_scaleSnapOffset; + m_initialScale = nonUniformScale; AZ::NonUniformScaleRequestBus::Event( m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, m_initialScale); @@ -51,29 +51,37 @@ namespace AzToolsFramework m_manipulators->InstallAxisLeftMouseDownCallback(mouseDownCallback); - m_manipulators->InstallAxisMouseMoveCallback([this](const LinearManipulator::Action& action) { - const AZ::Vector3 scaleMultiplier = - (AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale)); + m_manipulators->InstallAxisMouseMoveCallback( + [this](const LinearManipulator::Action& action) + { + const AZ::Vector3 scaleMultiplier = + (AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale)); - AZ::NonUniformScaleRequestBus::Event( - m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, - (scaleMultiplier * m_initialScale).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale))); - }); + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, + (scaleMultiplier * m_initialScale) + .GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale))); + }); m_manipulators->InstallUniformLeftMouseDownCallback(mouseDownCallback); - m_manipulators->InstallUniformMouseMoveCallback([this](const LinearManipulator::Action& action) { - const auto sumVectorElements = [](const AZ::Vector3& vec) { return vec.GetX() + vec.GetY() + vec.GetZ(); }; + m_manipulators->InstallUniformMouseMoveCallback( + [this](const LinearManipulator::Action& action) + { + const auto sumVectorElements = [](const AZ::Vector3& vec) + { + return vec.GetX() + vec.GetY() + vec.GetZ(); + }; - const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement(); - const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement(); - const float scaleMultiplier = AZ::GetClamp( - 1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier, - maxScaleMultiplier); + const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement(); + const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement(); + const float scaleMultiplier = AZ::GetClamp( + 1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier, + maxScaleMultiplier); - AZ::NonUniformScaleRequestBus::Event( - m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale); - }); + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale); + }); } NonUniformScaleComponentMode::~NonUniformScaleComponentMode() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 5acfa5df59..db321d6818 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -423,15 +423,14 @@ namespace AzToolsFramework } } - static void InitializeTranslationLookup( - EntityIdManipulators& entityIdManipulators, const AZ::Vector3& snapOffset) + static void InitializeTranslationLookup(EntityIdManipulators& entityIdManipulators) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); for (auto& entityIdLookup : entityIdManipulators.m_lookups) { entityIdLookup.second.m_initial = - AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first) + snapOffset); + AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first)); } } @@ -820,7 +819,7 @@ namespace AzToolsFramework // moving with ctrl - setting override pivotOverrideFrame.m_translationOverride = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - InitializeTranslationLookup(entityIdManipulators, -action.LocalPositionOffset()); + InitializeTranslationLookup(entityIdManipulators); } else { @@ -1277,12 +1276,12 @@ namespace AzToolsFramework // linear translationManipulators->InstallLinearManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const LinearManipulator::Action& action) mutable + [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable { // important to sort entityIds based on hierarchy order when updating transforms BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_positionSnapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -1302,19 +1301,19 @@ namespace AzToolsFramework }); translationManipulators->InstallLinearManipulatorMouseUpCallback( - [this](const LinearManipulator::Action& /*action*/) mutable + [this]([[maybe_unused]] const LinearManipulator::Action& action) mutable { EndRecordManipulatorCommand(); }); // planar translationManipulators->InstallPlanarManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const PlanarManipulator::Action& action) + [this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action) { // important to sort entityIds based on hierarchy order when updating transforms BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -1340,11 +1339,11 @@ namespace AzToolsFramework // surface translationManipulators->InstallSurfaceManipulatorMouseDownCallback( - [this, manipulatorEntityIds](const SurfaceManipulator::Action& action) + [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) { BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset); + InitializeTranslationLookup(m_entityIdManipulators); m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( @@ -3326,26 +3325,16 @@ namespace AzToolsFramework } static void DrawManipulatorGrid( - AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, - const float gridSize, const float localSnapping) + AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, const float gridSize) { const AZ::Matrix3x3 orientation = AZ::Matrix3x3::CreateFromTransform(entityIdManipulators.m_manipulators->GetLocalTransform()); - const AZ::Vector3 unsnappedTranslation = + const AZ::Vector3 translation = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - // calculate the offset to snap by to align the manipulator to the grid - // note: only perform this if we are not snapping in local space - const AZ::Vector3 snappedOffset = !localSnapping - ? CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisX(), gridSize) + - CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisY(), gridSize) - : AZ::Vector3::CreateZero(); - - const AZ::Vector3 snappedTranslation = unsnappedTranslation + snappedOffset; - DrawSnappingGrid( - debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, snappedTranslation), + debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, translation), gridSize); } @@ -3484,7 +3473,7 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(viewportInfo.m_viewportId); if (gridSnapParams.m_gridSnap && m_entityIdManipulators.m_manipulators) { - DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize, modifiers.Alt()); + DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize); } } } From b73de269ee5e271b0854b6ce30b54d2c839b1433 Mon Sep 17 00:00:00 2001 From: Aaron Ruiz Mora Date: Fri, 4 Jun 2021 15:24:22 +0100 Subject: [PATCH 100/153] Use '' instead of 'Default' in Material Selection widget. (#1140) --- Gems/PhysX/Code/Editor/MaterialIdWidget.cpp | 28 +++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp index 9ec438101a..44787ddd20 100644 --- a/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp +++ b/Gems/PhysX/Code/Editor/MaterialIdWidget.cpp @@ -19,6 +19,8 @@ namespace PhysX { namespace Editor { + static const char* const DefaultPhysicsMaterialLabel = ""; + AZ::u32 MaterialIdWidget::GetHandlerName() const { return Physics::Edit::MaterialIdSelector; @@ -72,8 +74,7 @@ namespace PhysX auto lockToDefault = [gui]() { - static const char* defaultLabel = "Default"; - gui->addItem(defaultLabel); + gui->addItem(DefaultPhysicsMaterialLabel); gui->setCurrentIndex(0); return false; }; @@ -83,30 +84,31 @@ namespace PhysX return lockToDefault(); } - auto materialAsset = AZ::Data::AssetManager::Instance().GetAsset(m_materialLibraryId, AZ::Data::AssetLoadBehavior::Default); - materialAsset.BlockUntilLoadComplete(); + auto materialLibraryAsset = AZ::Data::AssetManager::Instance().GetAsset(m_materialLibraryId, AZ::Data::AssetLoadBehavior::Default); + materialLibraryAsset.BlockUntilLoadComplete(); - if (materialAsset.Get() == nullptr) + if (materialLibraryAsset.Get() == nullptr) { return lockToDefault(); } - const auto& materialsData = materialAsset.Get()->GetMaterialsData(); + const auto& materials = materialLibraryAsset.Get()->GetMaterialsData(); - if (materialsData.size() == 0) + if (materials.empty()) { return lockToDefault(); } - m_libraryIds.reserve(materialsData.size()); + m_libraryIds.reserve(materials.size() + 1); // Plus one to reserve the first element for default physics material + // Add default physics material first m_libraryIds.push_back(Physics::MaterialId()); - gui->addItem("Default"); + gui->addItem(DefaultPhysicsMaterialLabel); - for (const auto& materialData : materialAsset.Get()->GetMaterialsData()) + for (const auto& material : materials) { - gui->addItem(materialData.m_configuration.m_surfaceType.c_str()); - m_libraryIds.push_back(materialData.m_id); + gui->addItem(material.m_configuration.m_surfaceType.c_str()); + m_libraryIds.push_back(material.m_id); } gui->setCurrentIndex(GetIndexForId(instance)); @@ -116,7 +118,7 @@ namespace PhysX Physics::MaterialId MaterialIdWidget::GetIdForIndex(size_t index) { - if (m_libraryIds.size() <= index) + if (index >= m_libraryIds.size()) { return Physics::MaterialId(); } From 5d4226df16a404708b69cb5a46e8aa297adb1767 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Fri, 4 Jun 2021 17:28:43 +0000 Subject: [PATCH 101/153] Get a mesh's morph targets based on the scene graph hierarchy, instead of mesh name (#1128) When building a mesh's morph targets, the exporter has to identify the base mesh in addition to each morph target mesh. Previously this was done by searching the entire scene graph for nodes * of type IBlendShapeData * whose parent's name matches the name of the Atom model This is problematic for a few reasons. The first is that the Atom model's name may have been based on the optimized mesh node. When this happens, the `OptimizedMeshSuffix` that is used in the Scene Graph node's name is stripped off of the Atom model's name. The result is that the *unoptimized* mesh is used as the base mesh for the blend shapes, instead of the optimized blend shape. This of course results in disaster, since the optimizer reorders the vertices, and the base mesh will not match the optimized one. The second is that it is not really necessary to do the search based on the node name at all. All of a mesh's blend shapes are child nodes of the base IMeshData node. With this change, the base mesh is located based on the node data pointer, and all of its child IBlendShapeData nodes are added to the set of blend shapes to process. This way, the Atom model's name isn't involved in the lookup. --- .../Model/MorphTargetExporter.cpp | 83 ++++++++----------- .../RPI.Builders/Model/MorphTargetExporter.h | 5 +- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp index 3d0cbca8e6..f14d73a9cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.cpp @@ -14,9 +14,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -27,62 +29,42 @@ namespace AZ::RPI AZStd::unordered_map MorphTargetExporter::GetBlendShapeInfos( const Containers::Scene& scene, - const AZStd::optional& filterMeshName) const + const MeshData* meshData) const { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); - const auto contentStorage = sceneGraph.GetContentStorage(); - const auto nameStorage = sceneGraph.GetNameStorage(); + + const auto foundBaseMeshIter = AZStd::find_if(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), [meshData](const auto& nodeData) + { + return nodeData.get() == meshData; + }); + if (foundBaseMeshIter == sceneGraph.GetContentStorage().cend()) + { + return {}; + } + + const auto baseMeshNodeIndex = sceneGraph.ConvertToNodeIndex(foundBaseMeshIter); + + const auto childBlendShapeDatas = Containers::MakeDerivedFilterView( + Containers::Views::MakeSceneGraphChildView(sceneGraph, baseMeshNodeIndex, sceneGraph.GetContentStorage().cbegin(), true) + ); AZStd::unordered_map result; - - const auto keyValueView = Containers::Views::MakePairView(nameStorage, contentStorage); - const auto filteredView = Containers::Views::MakeFilterView(keyValueView, Containers::DerivedTypeFilter()); - for (const auto& [name, object] : filteredView) + for (auto it = childBlendShapeDatas.cbegin(); it != childBlendShapeDatas.cend(); ++it) { - const Containers::SceneGraph::NodeIndex sceneNodeIndex = sceneGraph.Find(name.GetPath()); + const Containers::SceneGraph::NodeIndex blendShapeNodeIndex = sceneGraph.ConvertToNodeIndex(it.GetBaseIterator().GetBaseIterator().GetHierarchyIterator()); AZStd::set types; - Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, sceneNodeIndex); - if (types.find(Events::GraphMetaInfo::GetIgnoreVirtualType()) == types.end()) + Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, blendShapeNodeIndex); + if (!types.contains(Events::GraphMetaInfo::GetIgnoreVirtualType())) { - const char* sceneNodePath = name.GetPath(); - const Containers::SceneGraph::NodeIndex nodeIndex = sceneGraph.Find(sceneNodePath); - if (nodeIndex.IsValid()) - { - const AZStd::string meshNodeName = SourceBlendShapeInfo::GetMeshNodeName(sceneGraph, nodeIndex); - if (!filterMeshName.has_value() || - (filterMeshName.has_value() && filterMeshName.value() == meshNodeName)) - { - const AZStd::string blendShapeName = sceneGraph.GetNodeName(nodeIndex).GetName(); - SourceBlendShapeInfo& blendShapeInfo = result[blendShapeName]; - blendShapeInfo.m_sceneNodeIndices.push_back(nodeIndex); - } - } - else - { - AZ_Warning(ModelAssetBuilderComponent::s_builderName, false, "Cannot retrieve scene graph index for blend shape node with path %s.", sceneNodePath); - } + const AZStd::string blendShapeName{sceneGraph.GetNodeName(blendShapeNodeIndex).GetName(), sceneGraph.GetNodeName(blendShapeNodeIndex).GetNameLength()}; + result[blendShapeName].m_sceneNodeIndices.emplace_back(blendShapeNodeIndex); } } return result; } - AZStd::string MorphTargetExporter::SourceBlendShapeInfo::GetMeshNodeName(const Containers::SceneGraph& sceneGraph, - const Containers::SceneGraph::NodeIndex& sceneNodeIndex) - { - const auto* blendShapeData = - azrtti_cast(sceneGraph.GetNodeContent(sceneNodeIndex).get()); - AZ_Assert(blendShapeData, "Cannot get mesh node name from scene node. Node is expected to be a blend shape."); - if (blendShapeData) - { - Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - return sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); - } - - return {}; - } - void MorphTargetExporter::ProduceMorphTargets(const Containers::Scene& scene, uint32_t vertexOffset, const ModelAssetBuilderComponent::SourceMeshContent& sourceMesh, @@ -92,9 +74,14 @@ namespace AZ::RPI { const Containers::SceneGraph& sceneGraph = scene.GetGraph(); +#if defined(AZ_ENABLE_TRACING) + const auto baseMeshIt = AZStd::find(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), sourceMesh.m_meshData); + const Containers::SceneGraph::NodeIndex baseMeshIndex = sceneGraph.ConvertToNodeIndex(baseMeshIt); + const AZStd::string_view baseMeshName{sceneGraph.GetNodeName(baseMeshIndex).GetName(), sceneGraph.GetNodeName(baseMeshIndex).GetNameLength()}; +#endif + // Get the blend shapes for the given mesh - const AZStd::string_view meshName = sourceMesh.m_name.GetStringView(); - AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, meshName); + AZStd::unordered_map blendShapeInfos = GetBlendShapeInfos(scene, sourceMesh.m_meshData.get()); for (const auto& iter : blendShapeInfos) { @@ -109,12 +96,12 @@ namespace AZ::RPI { #if defined(AZ_ENABLE_TRACING) const Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex); - const char* meshNodeName = sceneGraph.GetNodeName(morphMeshParentIndex).GetName(); + const AZStd::string_view sourceMeshName{sceneGraph.GetNodeName(morphMeshParentIndex).GetName(), sceneGraph.GetNodeName(morphMeshParentIndex).GetNameLength()}; #endif - AZ_Assert(AZ::StringFunc::Equal(sourceMesh.m_name.GetCStr(), meshNodeName, /*bCaseSensitive=*/true), - "Scene graph mesh node (%s) has a different name than the product mesh (%s).", - meshNodeName, sourceMesh.m_name.GetCStr()); + AZ_Assert(AZ::StringFunc::Equal(baseMeshName, sourceMeshName, /*bCaseSensitive=*/true), + "Scene graph mesh node (%.*s) has a different name than the product mesh (%.*s).", + AZ_STRING_ARG(sourceMeshName), AZ_STRING_ARG(baseMeshName)); const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex); BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h index 4845d7d1da..32f9e2e508 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/MorphTargetExporter.h @@ -39,12 +39,9 @@ namespace AZ struct SourceBlendShapeInfo { AZStd::vector m_sceneNodeIndices; - - static AZStd::string GetMeshNodeName(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph, - const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& sceneNodeIndex); }; //! Retrieve all scene graph nodes per blend shape for all available blend shapes. - AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const AZStd::optional& filterMeshName = AZStd::nullopt) const; + AZStd::unordered_map GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const MeshData* meshData) const; //! Calculate position delta tolerance that is used to indicate whether a given vertex is part of the sparse set of morphed vertices //! or if it will be skipped and optimized out due to a hardly visible or no movement at all. From dcdd63966ed43ec80f56aca75c4ba9a80fcc201a Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Fri, 4 Jun 2021 10:28:56 -0700 Subject: [PATCH 102/153] ATOM-15658 Better option of CreateCommonBuffer requires unique buffer name (#1133) * ATOM-15658 Better option of CreateCommonBuffer requires unique buffer name - Change the CreateCommonBuffer function to not require an unique name by default. - Remove the code for generating unique buffer names. - Add buffer name to BufferAsset so it can be used for device object name instead of using asset file name. - Change RPI::Buffer to use BufferName_AssetUuid as attachment id. --- .../Source/CoreLights/LightCullingPass.cpp | 7 +--- .../Source/CoreLights/LightCullingRemap.cpp | 7 +--- .../Common/Code/Source/Math/MathFilter.cpp | 1 + .../ExposureControlSettings.cpp | 11 +----- .../ExposureControl/ExposureControlSettings.h | 4 +- .../DepthOfFieldReadBackFocusDepthPass.cpp | 3 +- .../ExposureControlRenderProxy.cpp | 1 + .../PostProcessing/EyeAdaptationPass.cpp | 6 +-- .../LuminanceHistogramGeneratorPass.cpp | 7 +--- .../RayTracing/RayTracingFeatureProcessor.cpp | 8 +--- .../Source/SkyBox/SkyBoxFeatureProcessor.cpp | 2 +- .../TransformServiceFeatureProcessor.cpp | 6 +-- .../Code/Source/Utils/GpuBufferHandler.cpp | 4 +- .../Include/Atom/RPI.Public/Buffer/Buffer.h | 2 + .../Atom/RPI.Public/Buffer/BufferSystem.h | 2 +- .../RPI.Public/Buffer/BufferSystemInterface.h | 5 ++- .../Atom/RPI.Reflect/Buffer/BufferAsset.h | 4 ++ .../Model/ModelAssetBuilderComponent.cpp | 2 +- .../Code/Source/RPI.Public/Buffer/Buffer.cpp | 17 ++++++--- .../Source/RPI.Public/Buffer/BufferSystem.cpp | 27 ++++++++----- .../DynamicDraw/DynamicBufferAllocator.cpp | 2 +- .../Source/RPI.Reflect/Buffer/BufferAsset.cpp | 8 +++- .../RPI.Reflect/Buffer/BufferAssetCreator.cpp | 5 ++- .../RPI/Code/Tests/Buffer/BufferTests.cpp | 38 +++++++++++++++---- .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 2 +- 25 files changed, 104 insertions(+), 77 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp index 987ed299b3..a9b43ef1e7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingPass.cpp @@ -311,14 +311,9 @@ namespace AZ { auto tileBufferResolution = GetTileDataBufferResolution(); - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LightList_%s", uuidString.c_str()); + desc.m_bufferName = "LightList"; desc.m_elementSize = sizeof(uint32_t); desc.m_byteCount = tileBufferResolution.m_width * tileBufferResolution.m_height * 256 * sizeof(uint32_t); m_lightList = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp index 42882cec6e..26e4ed9f6e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingRemap.cpp @@ -118,14 +118,9 @@ namespace AZ void LightCullingRemap::CreateRemappedLightListBuffer() { - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LightListRemapped_%s", uuidString.c_str()); + desc.m_bufferName = "LightListRemapped"; desc.m_elementSize = RHI::GetFormatSize(LightListRemappedFormat); desc.m_byteCount = m_tileDim.m_width * m_tileDim.m_height * NumBins * MaxLightsPerTile * desc.m_elementSize; m_lightListRemapped = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp b/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp index 8190c3af98..cb6f3e3522 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Math/MathFilter.cpp @@ -74,6 +74,7 @@ namespace AZ desc.m_elementFormat = filters.front()->GetElementFormat(); desc.m_byteCount = totalElementCount * elementSize; desc.m_bufferData = data.data(); + desc.m_isUniqueName = true; auto buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp index 056f7b7da4..288dd54e2b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp @@ -100,16 +100,9 @@ namespace AZ bool ExposureControlSettings::InitCommonBuffer() { - // generate a UUID for the buffer name to keep it unique - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - - AZStd::string bufferName = AZStd::string::format("%s_%s", ExposureControlBufferBaseName, uuidString.c_str()); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::Constant; - desc.m_bufferName = bufferName; + desc.m_bufferName = ExposureControlBufferName; desc.m_byteCount = sizeof(ShaderParameters); desc.m_elementSize = sizeof(ShaderParameters); @@ -117,7 +110,7 @@ namespace AZ if (!m_buffer) { - AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", bufferName.c_str()); + AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", desc.m_bufferName.c_str()); return false; } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h index 8344d6aa09..bfb4237b96 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.h @@ -28,8 +28,8 @@ namespace AZ { class PostProcessSettings; - // Base name of the buffer used for the exposure control feature. Usually distinct identifier will be added to this name for each exposure control settings. - static const char* const ExposureControlBufferBaseName = "ExposureControlBuffer"; + // Name of the buffer used for the exposure control feature + static const char* const ExposureControlBufferName = "ExposureControlBuffer"; // The post process sub-settings class for the exposure control feature class ExposureControlSettings final diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp index abd916fcc9..c355b7c8a7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldReadBackFocusDepthPass.cpp @@ -47,9 +47,8 @@ namespace AZ m_getDepthPass = static_cast(pass.get()); // Create buffer for read back focus depth. We append static counter to avoid name conflicts. - AZStd::string bufferName = AZStd::string::format("DepthOfFieldReadBackAutoFocusDepthBuffer_%d", s_bufferInstance++); RPI::CommonBufferDescriptor desc; - desc.m_bufferName = bufferName; + desc.m_bufferName = "DepthOfFieldReadBackAutoFocusDepthBuffer"; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; desc.m_byteCount = sizeof(float); desc.m_elementSize = aznumeric_cast(desc.m_byteCount); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp index eb7a3b527f..c70d56aa90 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/ExposureControlRenderProxy.cpp @@ -71,6 +71,7 @@ namespace AZ desc.m_bufferName = bufferName; desc.m_byteCount = sizeof(ShaderParameters); desc.m_elementSize = sizeof(ShaderParameters); + desc.m_isUniqueName = true; m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); } diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp index e7d4c47f02..bf293fd3d2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp @@ -34,7 +34,7 @@ namespace AZ { namespace Render { - static const char* const EyeAdaptationBufferBaseName = "EyeAdaptationBuffer"; + static const char* const EyeAdaptationBufferName = "EyeAdaptationBuffer"; RPI::Ptr EyeAdaptationPass::Create(const RPI::PassDescriptor& descriptor) { @@ -49,12 +49,10 @@ namespace AZ void EyeAdaptationPass::InitBuffer() { - AZStd::string bufferName = AZStd::string::format("%s_%p", EyeAdaptationBufferBaseName, this); - ExposureCalculationData defaultData; RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = bufferName; + desc.m_bufferName = EyeAdaptationBufferName; desc.m_byteCount = sizeof(ExposureCalculationData); desc.m_elementSize = aznumeric_cast(desc.m_byteCount); desc.m_bufferData = &defaultData; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp index 758c21bc4e..715ebf2945 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LuminanceHistogramGeneratorPass.cpp @@ -62,14 +62,9 @@ namespace AZ void LuminanceHistogramGeneratorPass::CreateHistogramBuffer() { - // generate a UUID for the buffer name to keep it unique when there are multiple render pipelines - AZ::Uuid uuid = AZ::Uuid::CreateRandom(); - AZStd::string uuidString; - uuid.ToString(uuidString); - RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite; - desc.m_bufferName = AZStd::string::format("LuminanceHistogramBuffer_%s", uuidString.c_str()); + desc.m_bufferName = "LuminanceHistogramBuffer"; desc.m_elementSize = sizeof(uint32_t); desc.m_byteCount = NumHistogramBins * sizeof(uint32_t); desc.m_elementFormat = RHI::Format::R32_UINT; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 10c7c2d378..2db396e36d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -210,12 +210,10 @@ namespace AZ if (m_meshInfoBuffer == nullptr) { - AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString(); - // allocate the MeshInfo structured buffer RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = AZStd::string::format("RayTracingMeshInfo_%s", uuidString.c_str()); + desc.m_bufferName = "RayTracingMeshInfo"; desc.m_byteCount = newMeshByteCount; desc.m_elementSize = sizeof(MeshInfo); m_meshInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); @@ -283,12 +281,10 @@ namespace AZ if (m_materialInfoBuffer == nullptr) { - AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString(); - // allocate the MaterialInfo structured buffer RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = AZStd::string::format("RayTracingMaterialInfo_%s", uuidString.c_str()); + desc.m_bufferName = "RayTracingMaterialInfo"; desc.m_byteCount = newMaterialByteCount; desc.m_elementSize = sizeof(MaterialInfo); m_materialInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp index 058e243fb7..4a3586a799 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkyBox/SkyBoxFeatureProcessor.cpp @@ -193,7 +193,7 @@ namespace AZ RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::Constant; - desc.m_bufferName = AZStd::string::format("SkyboxBuffer_%p", this); + desc.m_bufferName = "SkyboxBuffer"; desc.m_byteCount = byteCount; desc.m_elementSize = byteCount; desc.m_bufferData = &m_physicalSkyData; diff --git a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp index fb73d0f416..074b09e35d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/TransformService/TransformServiceFeatureProcessor.cpp @@ -89,13 +89,13 @@ namespace AZ // Create the transform buffer, grow by powers of two RPI::CommonBufferDescriptor desc2; desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldBuffer_%" PRIXPTR, reinterpret_cast(this)); + desc2.m_bufferName = "m_objectToWorldBuffer"; desc2.m_byteCount = byteCount; desc2.m_elementSize = elementSize; m_objectToWorldBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2); - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldHistoryBuffer_%p", this); + desc2.m_bufferName = "m_objectToWorldHistoryBuffer"; m_objectToWorldHistoryBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2); } else @@ -119,7 +119,7 @@ namespace AZ // Create the normal buffer, grow by powers of two RPI::CommonBufferDescriptor desc2; desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc2.m_bufferName = AZStd::string::format("'m_objectToWorldInverseTransposeBuffer_%" PRIXPTR, reinterpret_cast(this)); + desc2.m_bufferName = "m_objectToWorldInverseTransposeBuffer"; desc2.m_byteCount = byteCount; desc2.m_elementSize = elementSize; diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp index 13a151f8ac..db78247251 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/GpuBufferHandler.cpp @@ -40,13 +40,11 @@ namespace AZ if (m_bufferIndex.IsValid()) { - AZStd::string bufferName = AZStd::string::format("%s_%" PRIXPTR, descriptor.m_bufferName.c_str(), reinterpret_cast(this)); - uint32_t byteCount = RHI::NextPowerOfTwo(GetMax(BufferMinSize, m_elementCount * m_elementSize)); RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; - desc.m_bufferName = bufferName; + desc.m_bufferName = descriptor.m_bufferName; desc.m_byteCount = byteCount; desc.m_elementSize = descriptor.m_elementSize; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h index 3fef502e92..df24c7591b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/Buffer.h @@ -112,6 +112,8 @@ namespace AZ AZStd::mutex m_pendingUploadMutex; RHI::BufferViewDescriptor m_bufferViewDescriptor; + + RHI::AttachmentId m_attachmentId; }; template diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h index c4b6aa74b4..9f5b150752 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystem.h @@ -35,7 +35,7 @@ namespace AZ // BufferSystemInterface overrides... RHI::Ptr GetCommonBufferPool(CommonBufferPoolType poolType) override; Data::Instance CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) override; - Data::Instance FindCommonBuffer(AZStd::string_view bufferName) override; + Data::Instance FindCommonBuffer(AZStd::string_view uniqueBufferName) override; void Init(); void Shutdown(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h index 1469eed060..39b4b09691 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Buffer/BufferSystemInterface.h @@ -53,6 +53,9 @@ namespace AZ RHI::Format m_elementFormat = RHI::Format::Unknown; // CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) = 0; //! Find a buffer by name. The buffer has to be created by CreateBufferFromCommonPool function - virtual Data::Instance FindCommonBuffer(AZStd::string_view bufferName) = 0; + virtual Data::Instance FindCommonBuffer(AZStd::string_view uniqueBufferName) = 0; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h index d8a6fbb44d..4776933de6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h @@ -60,11 +60,15 @@ namespace AZ const Data::Asset& GetPoolAsset() const; CommonBufferPoolType GetCommonPoolType() const; + + const AZStd::string& GetName() const; private: // Called by asset creators to assign the asset to a ready state. void SetReady(); + AZStd::string m_name; + AZStd::vector m_buffer; RHI::BufferDescriptor m_bufferDescriptor; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp index ea2bdd0d83..f559a0aba6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp @@ -114,7 +114,7 @@ namespace AZ if (auto* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(26); // [ATOM-14992] + ->Version(27); // [ATOM-15658] } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp index 470b66c28e..81f02b7435 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/Buffer.cpp @@ -32,10 +32,6 @@ namespace AZ auto buffer = Data::InstanceDatabase::Instance().FindOrCreate( Data::InstanceId::CreateFromAssetId(bufferAsset.GetId()), bufferAsset); - if (buffer && buffer->m_rhiBuffer) - { - buffer->m_rhiBuffer->SetName(Name(bufferAsset.GetHint())); - } return buffer; } @@ -170,6 +166,16 @@ namespace AZ return resultCode; } } + + m_rhiBuffer->SetName(Name(bufferAsset.GetName())); + + // Only generate buffer's attachment id if the buffer is writable + if (RHI::CheckBitsAny(m_rhiBuffer->GetDescriptor().m_bindFlags, + RHI::BufferBindFlags::ShaderWrite | RHI::BufferBindFlags::CopyWrite | RHI::BufferBindFlags::DynamicInputAssembly)) + { + // attachment id = bufferName_bufferInstanceId + m_attachmentId = Name(bufferAsset.GetName() + "_" + bufferAsset.GetId().m_guid.ToString(false, false)); + } return RHI::ResultCode::Success; } @@ -312,7 +318,8 @@ namespace AZ const RHI::AttachmentId& Buffer::GetAttachmentId() const { - return m_rhiBuffer->GetName(); + AZ_Assert(!m_attachmentId.GetStringView().empty(), "Read-only buffer doesn't need attachment id"); + return m_attachmentId; } const RHI::BufferViewDescriptor& Buffer::GetBufferViewDescriptor() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp index 9a9254b0d6..c4b4b28d44 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Buffer/BufferSystem.cpp @@ -152,15 +152,22 @@ namespace AZ } Data::Instance BufferSystem::CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) - { - Uuid bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str()); - - // Report error if there is a buffer with same name. - // Note: this shouldn't return the existing buffer because users are expecting a newly created buffer. - if (Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId))) + { + Uuid bufferId; + if (descriptor.m_isUniqueName) { - AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str()); - return nullptr; + bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str()); + // Report error if there is a buffer with same name. + // Note: this shouldn't return the existing buffer because users are expecting a newly created buffer. + if (Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId))) + { + AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str()); + return nullptr; + } + } + else + { + bufferId = Uuid::CreateRandom(); } RHI::Ptr bufferPool = GetCommonBufferPool(descriptor.m_poolType); @@ -207,9 +214,9 @@ namespace AZ return nullptr; } - Data::Instance BufferSystem::FindCommonBuffer(AZStd::string_view bufferName) + Data::Instance BufferSystem::FindCommonBuffer(AZStd::string_view uniqueBufferName) { - Uuid bufferId = Uuid::CreateName(bufferName.data()); + Uuid bufferId = Uuid::CreateName(uniqueBufferName.data()); return Data::InstanceDatabase::Instance().Find(Data::InstanceId(bufferId)); } } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp index e79aa2e1bb..627b1e9912 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicBufferAllocator.cpp @@ -30,7 +30,7 @@ namespace AZ // Create the ring buffer from common pool RPI::CommonBufferDescriptor desc; desc.m_poolType = RPI::CommonBufferPoolType::DynamicInputAssembly; - desc.m_bufferName = AZStd::string::format("DyanmicBufferRing_%p", this); + desc.m_bufferName = "DyanmicBufferRing"; desc.m_elementSize = 1; desc.m_byteCount = ringBufferSize; m_ringBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp index 6f9d3a9d64..69444ae466 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAsset.cpp @@ -30,7 +30,8 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) + ->Field("Name", &BufferAsset::m_name) ->Field("Buffer", &BufferAsset::m_buffer) ->Field("BufferDescriptor", &BufferAsset::m_bufferDescriptor) ->Field("BufferViewDescriptor", &BufferAsset::m_bufferViewDescriptor) @@ -80,5 +81,10 @@ namespace AZ { return m_poolType; } + + const AZStd::string& BufferAsset::GetName() const + { + return m_name; + } } //namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp index 486be9860e..4bd1b53f57 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Buffer/BufferAssetCreator.cpp @@ -152,7 +152,10 @@ namespace AZ void BufferAssetCreator::SetBufferName(AZStd::string_view name) { - m_asset.SetHint(name); + if (ValidateIsReady()) + { + m_asset->m_name = name; + } } bool BufferAssetCreator::Clone(const Data::Asset& sourceAsset, Data::Asset& clonedResult, Data::AssetId& inOutLastCreatedAssetId) diff --git a/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp b/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp index df3af5f0d2..261b57a568 100644 --- a/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Buffer/BufferTests.cpp @@ -474,6 +474,7 @@ namespace UnitTest desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; desc.m_bufferName = "Buffer1"; desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount; + desc.m_isUniqueName = true; Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); // buffer created @@ -488,8 +489,33 @@ namespace UnitTest EXPECT_EQ(bufferFound2.get(), nullptr); } - // Failed if creates a buffer with duplicated name with existing buffer - TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffer_Fail) + // Failed if creates a buffe which has a same name with existing buffer + // and has m_isUniqueName is enabled + TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBufferEnableUniqueName_Fail) + { + using namespace AZ; + + ExpectedBuffer bufferInfo = CreateValidBuffer(); + + RPI::CommonBufferDescriptor desc; + desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly; + desc.m_bufferName = "Buffer1"; + desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount; + desc.m_isUniqueName = true; + + Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); + // buffer created + EXPECT_NE(bufferInst.get(), nullptr); + + AZ_TEST_START_ASSERTTEST; + Data::Instance bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); + AZ_TEST_STOP_ASSERTTEST(1); + // buffer NOT created + EXPECT_EQ(bufferInst2.get(), nullptr); + } + + // create a buffer which has a same name with existing buffer + TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffers_Success) { using namespace AZ; @@ -503,12 +529,10 @@ namespace UnitTest Data::Instance bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); // buffer created EXPECT_NE(bufferInst.get(), nullptr); - - AZ_TEST_START_ASSERTTEST; + Data::Instance bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc); - AZ_TEST_STOP_ASSERTTEST(1); - // buffer NOT created - EXPECT_EQ(bufferInst2.get(), nullptr); + // buffer created + EXPECT_NE(bufferInst2.get(), nullptr); } // Buffer instance creation unit tests diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index 8dc7f9387c..9f68a7d12c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -595,7 +595,7 @@ namespace AZ // Create a buffer and populate it with the transforms RPI::CommonBufferDescriptor descriptor; descriptor.m_bufferData = boneTransforms.data(); - descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s_%s", actorInstance->GetActor()->GetName(), Uuid::CreateRandom().ToString().c_str()); + descriptor.m_bufferName = AZStd::string::format("BoneTransformBuffer_%s", actorInstance->GetActor()->GetName()); descriptor.m_byteCount = boneTransforms.size() * sizeof(float); descriptor.m_elementSize = floatsPerBone * sizeof(float); descriptor.m_poolType = RPI::CommonBufferPoolType::ReadOnly; From 76a6df341b0b05eafb53f4977cd706a80a3b2b3d Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 10:51:47 -0700 Subject: [PATCH 103/153] SPEC-2513 Fixes to enable w4457 --- .../UdpTransport/UdpFragmentQueue.cpp | 4 +- Code/Sandbox/Editor/CVarMenu.cpp | 14 ++-- .../Editor/TrackView/TrackViewAnimNode.cpp | 4 +- .../Editor/TrackView/TrackViewTrack.cpp | 6 +- .../Vulkan/Code/Source/RHI/DescriptorSet.cpp | 4 +- .../Window/ShaderManagementConsoleWindow.cpp | 4 +- .../Source/Editor/QATLControlsTreeModel.cpp | 8 +- .../EMotionFX/Rendering/Common/RenderUtil.cpp | 12 +-- .../EMotionFX/Source/MultiThreadScheduler.cpp | 4 +- .../PropertyWidgets/MotionDataHandler.cpp | 6 +- .../StaticLib/GraphCanvas/Styling/Parser.cpp | 80 +++++++++---------- .../GraphCanvas/Utils/GraphUtils.cpp | 6 +- Gems/GraphModel/Code/Source/Model/Graph.cpp | 4 +- .../Editor/Animation/UiAnimViewAnimNode.cpp | 12 +-- .../Code/Editor/Animation/UiAnimViewTrack.cpp | 6 +- .../MicrophoneSystemComponent_Windows.cpp | 22 ++--- .../NetworkEntity/NetworkEntityManager.cpp | 4 +- .../Widgets/NodePalette/NodePaletteModel.cpp | 12 +-- .../View/Windows/ScriptCanvasContextMenus.cpp | 4 +- .../Grammar/AbstractCodeModel.cpp | 10 +-- .../Internal/Nodes/ExpressionNodeBase.cpp | 6 +- .../Code/Source/Core/WhiteBoxToolApi.cpp | 16 ++-- .../Common/MSVC/Configurations_msvc.cmake | 1 - 23 files changed, 124 insertions(+), 125 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp index 2a90509187..042f19aa70 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpFragmentQueue.cpp @@ -139,7 +139,7 @@ namespace AzNetworking NetworkOutputSerializer networkSerializer(buffer.GetBuffer(), buffer.GetSize()); { - ISerializer& serializer = networkSerializer; // To get the default typeinfo parameters in ISerializer + ISerializer& networkISerializer = networkSerializer; // To get the default typeinfo parameters in ISerializer // First, serialize out the header if (!header.SerializePacketFlags(networkSerializer)) @@ -148,7 +148,7 @@ namespace AzNetworking return false; } - if (!serializer.Serialize(header, "Header")) + if (!networkISerializer.Serialize(header, "Header")) { AZLOG(NET_FragmentQueue, "Reconstructed fragmented packet failed header serialization"); return false; diff --git a/Code/Sandbox/Editor/CVarMenu.cpp b/Code/Sandbox/Editor/CVarMenu.cpp index f3dd4cf065..bbce0c63fc 100644 --- a/Code/Sandbox/Editor/CVarMenu.cpp +++ b/Code/Sandbox/Editor/CVarMenu.cpp @@ -118,10 +118,10 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName, // Otherwise we could have just used the action's currently checked // state and updated the CVar's value only bool cVarOn = (cVar->GetFVal() == availableCVar.m_onValue); - bool checked = !cVarOn; - SetCVar(cVar, checked ? availableCVar.m_onValue : availableCVar.m_offValue); - action->setChecked(checked); - if (checked) + bool cVarChecked = !cVarOn; + SetCVar(cVar, cVarChecked ? availableCVar.m_onValue : availableCVar.m_offValue); + action->setChecked(cVarChecked); + if (cVarChecked) { // Set the rest of the CVars in the group to their off values SetCVarsToOffValue(availableCVars, availableCVar); @@ -132,9 +132,9 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName, // Initialize the action's checked state based on its associated CVar's current value ICVar* cVar = gEnv->pConsole->GetCVar(availableCVar.m_cVarName.toUtf8().data()); - bool checked = (cVar && cVar->GetFVal() == availableCVar.m_onValue); - action->setChecked(checked); - if (checked) + bool cVarChecked = (cVar && cVar->GetFVal() == availableCVar.m_onValue); + action->setChecked(cVarChecked); + if (cVarChecked) { // Set the rest of the CVars in the group to their off values SetCVarsToOffValue(availableCVars, availableCVar); diff --git a/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp b/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp index 35306b9535..2b4622f5ec 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewAnimNode.cpp @@ -205,10 +205,10 @@ CTrackViewAnimNode::CTrackViewAnimNode(IAnimSequence* pSequence, IAnimNode* anim for (int i = 0; i < nodeCount; ++i) { IAnimNode* node = pSequence->GetNode(i); - IAnimNode* pParentNode = node->GetParent(); + IAnimNode* pNodeParentNode = node->GetParent(); // If our node is the parent, then the current node is a child of it - if (animNode == pParentNode) + if (animNode == pNodeParentNode) { CTrackViewAnimNodeFactory animNodeFactory; CTrackViewAnimNode* pNewTVAnimNode = animNodeFactory.BuildAnimNode(pSequence, node, this); diff --git a/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp b/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp index 94559921c3..76a836f86c 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewTrack.cpp @@ -68,12 +68,12 @@ CTrackViewTrack::CTrackViewTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackA { // Search for child tracks const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount(); - for (unsigned int subTrackIndex = 0; subTrackIndex < subTrackCount; ++subTrackIndex) + for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI) { - IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackIndex); + IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI); CTrackViewTrackFactory trackFactory; - CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackIndex); + CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI); m_childNodes.push_back(std::unique_ptr(pNewTVTrack)); } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp index 634f5a51ac..37f1e31542 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp @@ -261,8 +261,8 @@ namespace AZ if (vulkanDescriptor.m_constantDataPool && constantDataSize) { m_constantDataBuffer = Buffer::Create(); - const RHI::BufferDescriptor descriptor(RHI::BufferBindFlags::Constant, constantDataSize); - RHI::BufferInitRequest request(*m_constantDataBuffer, descriptor); + const RHI::BufferDescriptor bufferDescriptor(RHI::BufferBindFlags::Constant, constantDataSize); + RHI::BufferInitRequest request(*m_constantDataBuffer, bufferDescriptor); RHI::ResultCode rhiResult = vulkanDescriptor.m_constantDataPool->InitBuffer(request); if (rhiResult != RHI::ResultCode::Success) { diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 6ab297bfc5..08d406884f 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -510,9 +510,9 @@ namespace ShaderManagementConsole AZStd::vector documentIdsToClose; documentIdsToClose.reserve(m_tabWidget->count()); const AZ::Uuid documentIdToKeepOpen = GetDocumentIdFromTab(tabIndex); - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + for (int tabI = 0; tabI < m_tabWidget->count(); ++tabI) { - const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + const AZ::Uuid documentId = GetDocumentIdFromTab(tabI); if (documentId != documentIdToKeepOpen) { documentIdsToClose.push_back(documentId); diff --git a/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp b/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp index d05f7830a4..32446237a3 100644 --- a/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp @@ -287,9 +287,9 @@ namespace AudioControls QDataStream stream(&encoded, QIODevice::ReadOnly); while (!stream.atEnd()) { - int row, col; + int streamRow, streamCol; QMap roleDataMap; - stream >> row >> col >> roleDataMap; + stream >> streamRow >> streamCol >> roleDataMap; if (!roleDataMap.isEmpty()) { // If dropping a folder, make sure that folder name doesn't already exist where it is being dropped @@ -341,9 +341,9 @@ namespace AudioControls { QByteArray data = mimeData->data(format); QDataStream stream(&data, QIODevice::ReadOnly); - int row, col; + int streamRow, streamCol; QMap roleDataMap; - stream >> row >> col >> roleDataMap; + stream >> streamRow >> streamCol >> roleDataMap; if (!roleDataMap.isEmpty() && roleDataMap[eDR_TYPE] != eIT_FOLDER) { return false; diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp index b2389a3086..90752c7604 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/Common/RenderUtil.cpp @@ -1628,18 +1628,18 @@ namespace MCommon } else { - const float screenWidth = static_cast(camera->GetScreenWidth()); - const float screenHeight = static_cast(camera->GetScreenHeight()); + const float cameraScreenWidth = static_cast(camera->GetScreenWidth()); + const float cameraScreenHeight = static_cast(camera->GetScreenHeight()); // find the 4 corners of the frustum AZ::Vector3 corners[4]; const AZ::Matrix4x4 inversedProjectionMatrix = MCore::InvertProjectionMatrix(camera->GetProjectionMatrix()); const AZ::Matrix4x4 inversedViewMatrix = MCore::InvertProjectionMatrix(camera->GetViewMatrix()); - corners[0] = MCore::Unproject(0.0f, 0.0f, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[1] = MCore::Unproject(screenWidth, 0.0f, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[2] = MCore::Unproject(screenWidth, screenHeight, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); - corners[3] = MCore::Unproject(0.0f, screenHeight, screenWidth, screenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[0] = MCore::Unproject(0.0f, 0.0f, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[1] = MCore::Unproject(cameraScreenWidth, 0.0f, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[2] = MCore::Unproject(cameraScreenWidth, cameraScreenHeight, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); + corners[3] = MCore::Unproject(0.0f, cameraScreenHeight, cameraScreenWidth, cameraScreenHeight, camera->GetFarClipDistance(), inversedProjectionMatrix, inversedViewMatrix); // calculate the intersection points with the ground plane and create an AABB around those // if there is no intersection point then use the ray target as point, which is the projection onto the far plane basically diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp index 327f9d27ae..1094ad72a3 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MultiThreadScheduler.cpp @@ -319,9 +319,9 @@ namespace EMotionFX step.mDependencies.Clear(false); // calculate the new dependencies for this step - for (ActorInstance* actorInstance : step.mActorInstances) + for (ActorInstance* stepActorInstance : step.mActorInstances) { - AddDependenciesToStep(actorInstance, &step); + AddDependenciesToStep(stepActorInstance, &step); } // assume that there is only one of the same actor instance in the whole schedule diff --git a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp index 7597cb888d..6060a81bd0 100644 --- a/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp +++ b/Gems/EMotionFX/Code/Source/Editor/PropertyWidgets/MotionDataHandler.cpp @@ -91,10 +91,10 @@ namespace EMotionFX } else { - AZ::Outcome index = factory.FindRegisteredIndexByTypeId(instance); - if (index.IsSuccess()) + AZ::Outcome motionIndex = factory.FindRegisteredIndexByTypeId(instance); + if (motionIndex.IsSuccess()) { - GUI->setCurrentIndex(static_cast(index.GetValue() + 1)); // +1 because we inserted an 'Automatic' one as first entry. + GUI->setCurrentIndex(static_cast(motionIndex.GetValue() + 1)); // +1 because we inserted an 'Automatic' one as first entry. } else { diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp index db07c3ca8e..23d28857e1 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/Parser.cpp @@ -725,23 +725,23 @@ namespace GraphCanvas case Attribute::LineColor: case Attribute::StripeColor: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsColorValid(value)) + if (IsColorValid(valueStr)) { - style->SetAttribute(attribute, ParseColor(value)); + style->SetAttribute(attribute, ParseColor(valueStr)); } break; } case Attribute::BackgroundImage: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (value.startsWith(QStringLiteral(":/"))) + if (valueStr.startsWith(QStringLiteral(":/"))) { - value = QString("qrc%1").arg(value); + valueStr = QString("qrc%1").arg(valueStr); } - QUrl url(value); + QUrl url(valueStr); if (url.isValid()) { style->SetAttribute(attribute, url); @@ -844,103 +844,103 @@ namespace GraphCanvas case Attribute::BorderStyle: case Attribute::LineStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsLineStyleValid(value)) + if (IsLineStyleValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseLineStyle(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseLineStyle(valueStr))); } break; } case Attribute::LineCurve: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsLineCurveValid(value)) + if (IsLineCurveValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseLineCurve(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseLineCurve(valueStr))); } break; } case Attribute::CapStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (IsCapStyleValid(value)) + if (IsCapStyleValid(valueStr)) { - style->SetAttribute(attribute, QVariant::fromValue(ParseCapStyle(value))); + style->SetAttribute(attribute, QVariant::fromValue(ParseCapStyle(valueStr))); } break; } case Attribute::FontFamily: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { - value = defaultFontInfo.family(); + valueStr = defaultFontInfo.family(); } else { - QFont font(value); + QFont font(valueStr); QFontInfo info(font); if (!info.exactMatch()) { - qWarning() << "Invalid font-family:" << value; + qWarning() << "Invalid font-family:" << valueStr; } } - style->SetAttribute(attribute, value); + style->SetAttribute(attribute, valueStr); } case Attribute::FontStyle: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFontInfo.style()); } else { - if (IsFontStyleValid(value)) + if (IsFontStyleValid(valueStr)) { - style->SetAttribute(attribute, ParseFontStyle(value)); + style->SetAttribute(attribute, ParseFontStyle(valueStr)); } } break; } case Attribute::FontWeight: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFontInfo.weight()); } else { - if (IsFontWeightValid(value)) + if (IsFontWeightValid(valueStr)) { - style->SetAttribute(attribute, ParseFontWeight(value)); + style->SetAttribute(attribute, ParseFontWeight(valueStr)); } } break; } case Attribute::FontVariant: { - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - if (QString::compare(value, QLatin1String("default"), Qt::CaseInsensitive) == 0) + if (QString::compare(valueStr, QLatin1String("default"), Qt::CaseInsensitive) == 0) { style->SetAttribute(attribute, defaultFont.capitalization()); } else { - if (IsFontVariantValid(value)) + if (IsFontVariantValid(valueStr)) { - style->SetAttribute(attribute, value); + style->SetAttribute(attribute, valueStr); } } break; @@ -965,23 +965,23 @@ namespace GraphCanvas break; case Attribute::PaletteStyle: { - QString value(member->value.GetString()); - style->SetAttribute(attribute, QVariant::fromValue(ParsePaletteStyle(value))); + QString valueStr(member->value.GetString()); + style->SetAttribute(attribute, QVariant::fromValue(ParsePaletteStyle(valueStr))); break; } case Attribute::PatternTemplate: case Attribute::PatternPalettes: { - QString value(member->value.GetString()); - style->SetAttribute(attribute, value); + QString valueStr(member->value.GetString()); + style->SetAttribute(attribute, valueStr); break; } case Attribute::Steps: { QList stepList; - QString value(member->value.GetString()); + QString valueStr(member->value.GetString()); - QStringList splitValues = value.split("|"); + QStringList splitValues = valueStr.split("|"); for (QString currentString : splitValues) { diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp index c2574a69f6..16bc3dd86a 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/GraphUtils.cpp @@ -1325,12 +1325,12 @@ namespace GraphCanvas AZStd::vector< Endpoint > endpoints; SlotRequestBus::EventResult(endpoints, currentEndpoint.GetSlotId(), &SlotRequests::GetRemappedModelEndpoints); - for (const Endpoint& endpoint : endpoints) + for (const Endpoint& e : endpoints) { // If we haven't already processed the node, add it to our explore set so we can recurse. - if (retVal.count(endpoint) == 0) + if (retVal.count(e) == 0) { - exploreSet.insert(endpoint); + exploreSet.insert(e); } } } diff --git a/Gems/GraphModel/Code/Source/Model/Graph.cpp b/Gems/GraphModel/Code/Source/Model/Graph.cpp index 25ad61db2c..809679e9f6 100644 --- a/Gems/GraphModel/Code/Source/Model/Graph.cpp +++ b/Gems/GraphModel/Code/Source/Model/Graph.cpp @@ -279,8 +279,8 @@ namespace GraphModel m_connections.erase(iter); #if defined(AZ_ENABLE_TRACING) - auto iter = AZStd::find(m_connections.begin(), m_connections.end(), connection); - AZ_Assert(iter == m_connections.end(), "Graph is broken. The same connection object was found multiple times."); + auto iterConnection = AZStd::find(m_connections.begin(), m_connections.end(), connection); + AZ_Assert(iterConnection == m_connections.end(), "Graph is broken. The same connection object was found multiple times."); #endif return true; diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp index f99eea5fa2..37629fac37 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewAnimNode.cpp @@ -110,10 +110,10 @@ CUiAnimViewAnimNode::CUiAnimViewAnimNode(IUiAnimSequence* pSequence, IUiAnimNode for (int i = 0; i < nodeCount; ++i) { IUiAnimNode* pNode = pSequence->GetNode(i); - IUiAnimNode* pParentNode = pNode->GetParent(); + IUiAnimNode* pNodeParentNode = pNode->GetParent(); // If our node is the parent, then the current node is a child of it - if (pAnimNode == pParentNode) + if (pAnimNode == pNodeParentNode) { CUiAnimViewAnimNodeFactory animNodeFactory; CUiAnimViewAnimNode* pNewUiAVAnimNode = animNodeFactory.BuildAnimNode(pSequence, pNode, this); @@ -510,20 +510,20 @@ bool CUiAnimViewAnimNode::BaseClassPropertyPotentiallyChanged( { for (const AZ::SerializeContext::ClassElement& baseElement : baseClassData->m_elements) { - size_t offset = baseClassOffset + baseElement.m_offset; + size_t baseOffset = baseClassOffset + baseElement.m_offset; if (baseElement.m_flags & AZ::SerializeContext::ClassElement::FLG_BASE_CLASS) { - if (BaseClassPropertyPotentiallyChanged(context, dstComponent, srcComponent, baseElement, offset)) + if (BaseClassPropertyPotentiallyChanged(context, dstComponent, srcComponent, baseElement, baseOffset)) { valueChanged = true; } } else { - if (HasComponentParamValueAzChanged(dstComponent, srcComponent, baseElement, offset)) + if (HasComponentParamValueAzChanged(dstComponent, srcComponent, baseElement, baseOffset)) { valueChanged = true; - AzEntityPropertyChanged(srcComponent, dstComponent, baseElement, offset); + AzEntityPropertyChanged(srcComponent, dstComponent, baseElement, baseOffset); } } } diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp index 797154a50b..fc77a370d3 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewTrack.cpp @@ -59,12 +59,12 @@ CUiAnimViewTrack::CUiAnimViewTrack(IUiAnimTrack* pTrack, CUiAnimViewAnimNode* pT { // Search for child tracks const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount(); - for (unsigned int subTrackIndex = 0; subTrackIndex < subTrackCount; ++subTrackIndex) + for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI) { - IUiAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackIndex); + IUiAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI); CUiAnimViewTrackFactory trackFactory; - CUiAnimViewTrack* pNewUiAVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackIndex); + CUiAnimViewTrack* pNewUiAVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI); m_childNodes.push_back(std::unique_ptr(pNewUiAVTrack)); } diff --git a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp index 2eb840b253..5a080084e1 100644 --- a/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp +++ b/Gems/Microphone/Code/Source/Platform/Windows/MicrophoneSystemComponent_Windows.cpp @@ -422,12 +422,12 @@ namespace Audio if (stereoToMono) { // Samples are interleaved now, copy only left channel to the output - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float* outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float* bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - outputData[frame] = *inputData++; - ++inputData; + bufferOutputData[frame] = *bufferInputData++; + ++bufferInputData; } } else // monoToStereo @@ -435,21 +435,21 @@ namespace Audio // Split single samples to both left and right channels if (shouldDeinterleave) { - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float** outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float** bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - outputData[0][frame] = outputData[1][frame] = inputData[frame]; + bufferOutputData[0][frame] = bufferOutputData[1][frame] = bufferInputData[frame]; } } else { - float* inputData = reinterpret_cast(m_conversionBufferIn.m_data); - float* outputData = reinterpret_cast(m_conversionBufferOut.m_data); + float* bufferInputData = reinterpret_cast(m_conversionBufferIn.m_data); + float* bufferOutputData = reinterpret_cast(m_conversionBufferOut.m_data); for (AZ::u32 frame = 0; frame < numFrames; ++frame) { - *outputData++ = inputData[frame]; - *outputData++ = inputData[frame]; + *bufferOutputData++ = bufferInputData[frame]; + *bufferOutputData++ = bufferInputData[frame]; } } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index eaf89f3489..b0f1b221e8 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -263,9 +263,9 @@ namespace Multiplayer // Validate that we aren't already planning to remove this entity if (safeToExit) { - for (auto entityId : m_removeList) + for (auto remoteEntityId : m_removeList) { - if (entityId == entityId) + if (remoteEntityId == remoteEntityId) { safeToExit = false; } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp index 8b00b5b71b..a5c0287cfd 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/NodePaletteModel.cpp @@ -340,31 +340,31 @@ namespace } // Pass in the associated class data so we can do more intensive lookups? - const AZ::SerializeContext::ClassData* classData = serializeContext.FindClassData(node.first); + const AZ::SerializeContext::ClassData* nodeClassData = serializeContext.FindClassData(node.first); - if (classData == nullptr) + if (nodeClassData == nullptr) { continue; } // Detect primitive types os we avoid making nodes out of them. // Or anything that is 'pure data' and should be populated through a different mechanism. - if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } // Skip over some of our more dynamic nodes that we want to populate using different means - else if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + else if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } - else if (classData->m_azRtti && classData->m_azRtti->IsTypeOf()) + else if (nodeClassData->m_azRtti && nodeClassData->m_azRtti->IsTypeOf()) { continue; } else { - nodePaletteModel.RegisterCustomNode(categoryPath, node.first, node.second, classData); + nodePaletteModel.RegisterCustomNode(categoryPath, node.first, node.second, nodeClassData); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp index 428f5eb290..3c21701fb0 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/ScriptCanvasContextMenus.cpp @@ -563,13 +563,13 @@ namespace ScriptCanvasEditor else if (slotType == GraphCanvas::SlotTypes::DataSlot) { const AZ::EntityId& slotId2 = GetTargetId(); - const GraphCanvas::GraphId& graphId = GetGraphId(); + const GraphCanvas::GraphId& graphId2 = GetGraphId(); GraphCanvas::Endpoint endpoint; GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId2, &GraphCanvas::SlotRequests::GetEndpoint); bool promotedElement = false; - GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint); + GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint); if (promotedElement) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index db45f6bfe3..2a485c9501 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -4090,23 +4090,23 @@ namespace ScriptCanvas auto userFunctionIter = m_userInsThatRequireTopology.find(nodeling); if (userFunctionIter != m_userInsThatRequireTopology.end()) { - auto& node = *userFunctionIter->first; - auto outSlots = node.GetSlotsByType(CombinedSlotType::ExecutionOut); + auto& userFunctionNode = *userFunctionIter->first; + auto outSlots = userFunctionNode.GetSlotsByType(CombinedSlotType::ExecutionOut); if (outSlots.empty() || !outSlots.front()) { - AddError(node.GetEntityId(), nullptr, ScriptCanvas::ParseErrors::NoOutSlotInFunctionDefinitionStart); + AddError(userFunctionNode.GetEntityId(), nullptr, ScriptCanvas::ParseErrors::NoOutSlotInFunctionDefinitionStart); return; } - if (!ExecutionContainsCyclesCheck(node, *outSlots.front())) + if (!ExecutionContainsCyclesCheck(userFunctionNode, *outSlots.front())) { auto definition = userFunctionIter->second; auto entrySlot = definition->GetId().m_slot; AZ_Assert(entrySlot, "Bad accounting in user function definition node"); AZStd::vector returnValues; UserOutCallCollector userOutCallCollector; - TraverseExecutionConnections(node, *entrySlot, userOutCallCollector); + TraverseExecutionConnections(userFunctionNode, *entrySlot, userOutCallCollector); const AZStd::unordered_set& uniqueNodelingsOut = userOutCallCollector.GetOutCalls(); for (const auto& returnCall : uniqueNodelingsOut) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp index e7edcce002..8c0f5760a8 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Internal/Nodes/ExpressionNodeBase.cpp @@ -121,13 +121,13 @@ namespace ScriptCanvas { if (slotId == ExpressionNodeBaseProperty::GetInSlotId(this)) { - for (const SlotId& slotId : m_dirtyInputs) + for (const SlotId& dirtySlotId : m_dirtyInputs) { - auto variableIter = m_slotToVariableMap.find(slotId); + auto variableIter = m_slotToVariableMap.find(dirtySlotId); if (variableIter != m_slotToVariableMap.end()) { - PushVariable(variableIter->second, (*FindDatum(slotId))); + PushVariable(variableIter->second, (*FindDatum(dirtySlotId))); } } diff --git a/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp b/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp index 5803f066ae..a6b9456f98 100644 --- a/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp +++ b/Gems/WhiteBox/Code/Source/Core/WhiteBoxToolApi.cpp @@ -2060,23 +2060,23 @@ namespace WhiteBox polygonHandle.m_faceHandles.push_back(faceHandleToVisit); // for all halfedges - for (const auto halfedgeHandle : faceHalfedges) + for (const auto faceHalfedgeHandle : faceHalfedges) { - const EdgeHandle edgeHandle = HalfedgeEdgeHandle(whiteBox, halfedgeHandle); + const EdgeHandle edgeHandle = HalfedgeEdgeHandle(whiteBox, faceHalfedgeHandle); // if we haven't seen this halfedge before and we want to track it, // store it in visited halfedges - if (halfedgeHandle != oppositeHalfedgeHandle + if (faceHalfedgeHandle != oppositeHalfedgeHandle // ignore border halfedges (not inside the polygon) - && AZStd::find(borderHalfedgeHandles.cbegin(), borderHalfedgeHandles.cend(), halfedgeHandle) == + && AZStd::find(borderHalfedgeHandles.cbegin(), borderHalfedgeHandles.cend(), faceHalfedgeHandle) == borderHalfedgeHandles.cend() // ensure we do not visit the same halfedge again - && AZStd::find(visitedHalfedges.cbegin(), visitedHalfedges.cend(), halfedgeHandle) == + && AZStd::find(visitedHalfedges.cbegin(), visitedHalfedges.cend(), faceHalfedgeHandle) == visitedHalfedges.cend() // ignore the halfedge if we've already tracked it in our 'building' list && AZStd::find(buildingEdgeHandles.cbegin(), buildingEdgeHandles.cend(), edgeHandle) == buildingEdgeHandles.cend()) { - halfedgesToVisit.push_back(HalfedgeOppositeHalfedgeHandle(whiteBox, halfedgeHandle)); + halfedgesToVisit.push_back(HalfedgeOppositeHalfedgeHandle(whiteBox, faceHalfedgeHandle)); } } } @@ -3198,10 +3198,10 @@ namespace WhiteBox // - add bottom faces if mesh was 2d previously (reverse winding order) FaceHandles allFacesToRemove = polygonHandle.m_faceHandles; - for (const auto& polygonHandle : polygonHandlesToRemove) + for (const auto& polygonHandleToRemove : polygonHandlesToRemove) { allFacesToRemove.insert( - allFacesToRemove.end(), polygonHandle.m_faceHandles.cbegin(), polygonHandle.m_faceHandles.cend()); + allFacesToRemove.end(), polygonHandleToRemove.m_faceHandles.cbegin(), polygonHandleToRemove.m_faceHandles.cend()); } // remove all faces that were already there diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index f53b8aa769..357d578c44 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -73,7 +73,6 @@ ly_append_configurations_options( /wd4389 # comparison, signed/unsigned mismatch /wd4436 # the result of unary operator may be unaligned /wd4450 # declaration hides global declaration - /wd4457 # declaration hides function parameter # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From 1f48985a0e325164af62561f6983ebac4a620e0c Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Fri, 4 Jun 2021 18:09:26 +0000 Subject: [PATCH 104/153] Update Blast to the latest version, eb169fe (#1076) --- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index fa1326b63d..1a2cfa4049 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -30,11 +30,11 @@ ly_associate_package(PACKAGE_NAME azslc-1.7.21-rev1-multiplatform ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) -ly_associate_package(PACKAGE_NAME Blast-1.1.7-rev1-multiplatform TARGETS Blast PACKAGE_HASH 36b8f393bcd25d0f85cfc7a831ebbdac881e6054c4f0735649966aa6aa86e6f0) ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform TARGETS PVRTexTool PACKAGE_HASH d0d6da61c7557de0d2c71fc35ba56c3be49555b703f0e853d4c58225537acf1e) # platform-specific: ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0) +ly_associate_package(PACKAGE_NAME Blast-v1.1.7_rc2-9-geb169fe-rev1-windows TARGETS Blast PACKAGE_HASH 216df71f4ffaf4a6ea3f2e77e5f27d68f2325e717fbd1626b00c785b82cd1b67) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev2-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH decc53e97c7ddda9c7f853a30af7808a7b652a912f59ad2cd4bca5d308aae2c4) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817) ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-windows TARGETS freetype PACKAGE_HASH 88dedc86ccb8c92f14c2c033e51ee7d828fa08eafd6475c6aa963938a99f4bf3) From febf53671eacbe0f67a60feb5317ef93d70f43f5 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Fri, 4 Jun 2021 11:09:44 -0700 Subject: [PATCH 105/153] Addressed PR feedback. --- .../AzCore/AzCore/Serialization/IdUtils.h | 2 +- .../Spawnable/SpawnableEntitiesInterface.h | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h index 98959fe4bd..15ce299000 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h +++ b/Code/Framework/AzCore/AzCore/Serialization/IdUtils.h @@ -29,7 +29,7 @@ namespace AZ namespace IdUtils { /** - * \param AllowDuplicates - If true allows the same id to be registered multiple time, + * \param AllowDuplicates - If true allows the same id to be registered multiple times, with the newer value overwriting the stored value. If false, duplicates are not allowed and the first stored value is kept.The default is false. */ diff --git a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h index 2ad1db60a4..d2a5872fc8 100644 --- a/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Spawnable/SpawnableEntitiesInterface.h @@ -177,8 +177,8 @@ namespace AzFramework //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. EntityPreInsertionCallback m_preInsertionCallback; - //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that - //! made the function call. The returned list of entities contains all the newly created entities. + //! Callback that's called when spawning entities has completed. This can be triggered from a different thread than the one that + //! made the function call to spawn. The returned list of entities contains all the newly created entities. EntitySpawnCallback m_completionCallback; //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. AZ::SerializeContext* m_serializeContext { nullptr }; @@ -191,8 +191,8 @@ namespace AzFramework //! Callback that's called after instances of entities have been created, but before they're spawned into the world. This //! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components. EntityPreInsertionCallback m_preInsertionCallback; - //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that - //! made the function call. The returned list of entities contains all the newly created entities. + //! Callback that's called when spawning entities has completed. This can be triggered from a different thread than the one that + //! made the function call to spawn. The returned list of entities contains all the newly created entities. EntitySpawnCallback m_completionCallback; //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. AZ::SerializeContext* m_serializeContext{ nullptr }; @@ -207,8 +207,8 @@ namespace AzFramework struct DespawnAllEntitiesOptionalArgs final { - //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that - //! made the function call. The returned list of entities contains all the newly created entities. + //! Callback that's called when despawning entities has completed. This can be triggered from a different thread than the one that + //! made the function call to despawn. The returned list of entities contains all the newly created entities. EntityDespawnCallback m_completionCallback; //! The priority at which this call will be executed. SpawnablePriority m_priority { SpawnablePriority_Default }; @@ -216,10 +216,10 @@ namespace AzFramework struct ReloadSpawnableOptionalArgs final { - //! Callback that's called when spawning entities has completed. This can be called from a different thread than the one that - //! made the function call. The returned list of entities contains all the newly created entities. + //! Callback that's called when respawning entities has completed. This can be triggered from a different thread than the one that + //! made the function call to respawn. The returned list of entities contains all the newly created entities. ReloadSpawnableCallback m_completionCallback; - //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used. + //! The Serialize Context used to clone entities with. If this is not provided the global Serialize Context will be used. AZ::SerializeContext* m_serializeContext { nullptr }; //! The priority at which this call will be executed. SpawnablePriority m_priority { SpawnablePriority_Default }; @@ -268,32 +268,32 @@ namespace AzFramework //! Spawn instances of all entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. - //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs + //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs. virtual void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; //! Spawn instances of some entities in the spawnable. //! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them. //! @param priority The priority at which this call will be executed. //! @param entityIndices The indices into the template entities stored in the spawnable that will be used to spawn entities from. - //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs + //! @param optionalArgs Optional additional arguments, see SpawnEntitiesOptionalArgs. virtual void SpawnEntities( EntitySpawnTicket& ticket, AZStd::vector entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment. //! @param ticket The ticket previously used to spawn entities with. //! @param priority The priority at which this call will be executed. - //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs + //! @param optionalArgs Optional additional arguments, see DespawnAllEntitiesOptionalArgs. virtual void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0; //! Removes all entities in the provided list from the environment and reconstructs the entities from the provided spawnable. //! @param ticket Holds the information on the entities to reload. //! @param priority The priority at which this call will be executed. //! @param spawnable The spawnable that will replace the existing spawnable. Both need to have the same asset id. - //! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs + //! @param optionalArgs Optional additional arguments, see ReloadSpawnableOptionalArgs. virtual void ReloadSpawnable( EntitySpawnTicket& ticket, AZ::Data::Asset spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) = 0; //! List all entities that are spawned using this ticket. //! @param ticket Only the entities associated with this ticket will be listed. - //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to list the entities on. + //! @param optionalArgs Optional additional arguments, see ListEntitiesOptionalArgs. virtual void ListEntities( EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0; //! List all entities that are spawned using this ticket with their spawnable index. @@ -303,23 +303,23 @@ namespace AzFramework //! the same index may appear multiple times as there are no restriction on how many instance of a specific entity can be //! created. //! @param ticket Only the entities associated with this ticket will be listed. - //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to list the entities and indices on. + //! @param optionalArgs Optional additional arguments, see ListEntitiesOptionalArgs. virtual void ListIndicesAndEntities( EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0; //! Claim all entities that are spawned using this ticket. Ownership of the entities is transferred from the ticket to the //! caller through the callback. After this call the ticket will have no entities associated with it. The caller of //! this function will need to manage the entities after this call. //! @param ticket Only the entities associated with this ticket will be released. - //! @param priority The priority at which this call will be executed. //! @param listCallback Required callback that will be called to transfer the entities through. + //! @param optionalArgs Optional additional arguments, see ClaimEntitiesOptionalArgs. virtual void ClaimEntities( EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs = {}) = 0; //! Blocks until all operations made on the provided ticket before the barrier call have completed. //! @param ticket The ticket to monitor. - //! @param priority The priority at which this call will be executed. //! @param completionCallback Required callback that will be called as soon as the barrier has been reached. + //! @param optionalArgs Optional additional arguments, see BarrierOptionalArgs. virtual void Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) = 0; //! Register a handler for OnSpawned events. From b10ed227c0d7a59d51b6397a4f25a4b395293ae8 Mon Sep 17 00:00:00 2001 From: guthadam Date: Fri, 4 Jun 2021 13:54:45 -0500 Subject: [PATCH 106/153] Added version handling for removed fields --- .../Code/Source/Material/EditorMaterialComponentSlot.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index bdc82acda6..65fa7bc286 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -70,6 +70,12 @@ namespace AZ } } + if (classElement.GetVersion() < 5) + { + classElement.RemoveElementByName(AZ_CRC_CE("matModUvOverrides")); + classElement.RemoveElementByName(AZ_CRC_CE("propertyOverrides")); + } + return true; } From 758f62a5531b3a28c10d8e410645a022868976cd Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Fri, 4 Jun 2021 12:34:50 -0700 Subject: [PATCH 107/153] Fix Editor crash in Mac --- Registry/Platform/Mac/streamer.editor.setreg | 28 ++++++++++++++++++++ Registry/Platform/Mac/streamer.test.setreg | 24 +++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 Registry/Platform/Mac/streamer.editor.setreg create mode 100644 Registry/Platform/Mac/streamer.test.setreg diff --git a/Registry/Platform/Mac/streamer.editor.setreg b/Registry/Platform/Mac/streamer.editor.setreg new file mode 100644 index 0000000000..85360d128e --- /dev/null +++ b/Registry/Platform/Mac/streamer.editor.setreg @@ -0,0 +1,28 @@ +{ + "Amazon": + { + "AzCore": + { + "Streamer": + { + "Profiles": + { + "Generic": + { + "Stack": + [ + { + "$type": "AZ::IO::StorageDriveConfig", + // The maximum number of file handles that the drive will cache. + // On Mac the default limit for the number of file handles an application + // can have open is set to 256. So we need to set this to a lower value than on PC. + // This limit is set by "launchctl limit maxfiles" + "MaxFileHandles": 65 + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/Registry/Platform/Mac/streamer.test.setreg b/Registry/Platform/Mac/streamer.test.setreg new file mode 100644 index 0000000000..df41b7a350 --- /dev/null +++ b/Registry/Platform/Mac/streamer.test.setreg @@ -0,0 +1,24 @@ +{ + "Amazon": + { + "AzCore": + { + "Streamer": + { + "Profiles": + { + "Generic": + { + "Stack": + [ + { + "$type": "AZ::IO::StorageDriveConfig", + "MaxFileHandles": 65 + } + ] + } + } + } + } + } +} \ No newline at end of file From 16eb3bd82c9fa842b6f654115607e50bf7a5a65e Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:25:49 -0500 Subject: [PATCH 108/153] Adding newline to streamer.editor.setreg --- Registry/Platform/Mac/streamer.editor.setreg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Registry/Platform/Mac/streamer.editor.setreg b/Registry/Platform/Mac/streamer.editor.setreg index 85360d128e..2fc8197c5f 100644 --- a/Registry/Platform/Mac/streamer.editor.setreg +++ b/Registry/Platform/Mac/streamer.editor.setreg @@ -25,4 +25,4 @@ } } } -} \ No newline at end of file +} From f7caa988081eca13d0680eb89eed5af5a795224f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:26:16 -0500 Subject: [PATCH 110/153] Adding newline to streamer.test.setreg --- Registry/Platform/Mac/streamer.test.setreg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Registry/Platform/Mac/streamer.test.setreg b/Registry/Platform/Mac/streamer.test.setreg index df41b7a350..2b053a497e 100644 --- a/Registry/Platform/Mac/streamer.test.setreg +++ b/Registry/Platform/Mac/streamer.test.setreg @@ -21,4 +21,4 @@ } } } -} \ No newline at end of file +} From 40d90c49a378bb82c1632fb1e29fbc6b7bd76774 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Fri, 4 Jun 2021 13:42:25 -0700 Subject: [PATCH 111/153] Disabled writing UserSettings.xml in Spawnable tests. --- .../Tests/Spawnable/SpawnableEntitiesManagerTests.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp index 484b7f46d7..8bb39449f1 100644 --- a/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp +++ b/Code/Framework/Tests/Spawnable/SpawnableEntitiesManagerTests.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -40,6 +41,10 @@ namespace UnitTest m_application = new TestApplication(); AZ::ComponentApplication::Descriptor descriptor; m_application->Start(descriptor); + // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // in the unit tests. + AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); m_spawnable = aznew AzFramework::Spawnable( AZ::Data::AssetId::CreateString("{EB2E8A2B-F253-4A90-BBF4-55F2EED786B8}:0"), AZ::Data::AssetData::AssetStatus::Ready); From 55a46806590d04c45b3203fa27b5216536677100 Mon Sep 17 00:00:00 2001 From: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:10:30 -0700 Subject: [PATCH 112/153] Fixed Multiplayer unit tests. The multiplayer unit tests created a SpawnableSystemComponent without an application to provide the Serialize Context. This caused an assert which failed the unit tests. Since the entity spawning system doesn't seem to be directly used the component was removed. --- Gems/Multiplayer/Code/Tests/MultiplayerSystemTests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Tests/MultiplayerSystemTests.cpp b/Gems/Multiplayer/Code/Tests/MultiplayerSystemTests.cpp index 6ace4db592..7b09b65de4 100644 --- a/Gems/Multiplayer/Code/Tests/MultiplayerSystemTests.cpp +++ b/Gems/Multiplayer/Code/Tests/MultiplayerSystemTests.cpp @@ -30,7 +30,6 @@ namespace UnitTest { SetupAllocator(); AZ::NameDictionary::Create(); - m_spawnableComponent = new AzFramework::SpawnableSystemComponent(); m_netComponent = new AzNetworking::NetworkingSystemComponent(); m_mpComponent = new Multiplayer::MultiplayerSystemComponent(); @@ -46,7 +45,6 @@ namespace UnitTest { delete m_mpComponent; delete m_netComponent; - delete m_spawnableComponent; AZ::NameDictionary::Destroy(); TeardownAllocator(); } @@ -76,7 +74,6 @@ namespace UnitTest AzNetworking::NetworkingSystemComponent* m_netComponent = nullptr; Multiplayer::MultiplayerSystemComponent* m_mpComponent = nullptr; - AzFramework::SpawnableSystemComponent* m_spawnableComponent = nullptr; }; TEST_F(MultiplayerSystemTests, TestInitEvent) From 50d6e36ccd17c9214f057e749dc73db5a2c148b8 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 14:36:46 -0700 Subject: [PATCH 113/153] Bug and improvements to Editor/AP debugging settings (#1146) --- Code/Sandbox/Editor/CMakeLists.txt | 4 ++-- Code/Tools/AssetProcessor/CMakeLists.txt | 4 ++-- cmake/Projects.cmake | 12 +++++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt index 01b58e3f77..58d5e86a2f 100644 --- a/Code/Sandbox/Editor/CMakeLists.txt +++ b/Code/Sandbox/Editor/CMakeLists.txt @@ -191,8 +191,8 @@ ly_add_translations( ) ly_add_dependencies(Editor AssetProcessor) -if(LY_FIRST_PROJECT_PATH) - set_property(TARGET Editor APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"") +if(LY_DEFAULT_PROJECT_PATH) + set_property(TARGET Editor APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\"") endif() ################################################################################ diff --git a/Code/Tools/AssetProcessor/CMakeLists.txt b/Code/Tools/AssetProcessor/CMakeLists.txt index 6c12ab6024..2db888218b 100644 --- a/Code/Tools/AssetProcessor/CMakeLists.txt +++ b/Code/Tools/AssetProcessor/CMakeLists.txt @@ -125,8 +125,8 @@ ly_add_target( AZ::AssetProcessorBatch.Static ) -if(LY_FIRST_PROJECT_PATH) - set_property(TARGET AssetProcessor AssetProcessorBatch APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"") +if(LY_DEFAULT_PROJECT_PATH) + set_property(TARGET AssetProcessor AssetProcessorBatch APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\"") endif() # Adds the AssetProcessorBatch target as a C preprocessor define so that it can be used as a Settings Registry diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index adaf7ee15f..eadfa79c1b 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -167,9 +167,6 @@ endfunction() # Add the projects here so the above function is found foreach(project ${LY_PROJECTS}) file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) - if(NOT LY_FIRST_PROJECT) - ly_set(LY_FIRST_PROJECT_PATH ${full_directory_path}) - endif() string(SHA256 full_directory_hash ${full_directory_path}) # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit @@ -182,4 +179,13 @@ foreach(project ${LY_PROJECTS}) ly_generate_project_build_path_setreg(${full_directory_path}) add_project_json_external_subdirectories(${full_directory_path}) endforeach() + +# If just one project is defined we pass it as a parameter to the applications +list(LENGTH LY_PROJECTS projects_length) +if(projects_length EQUAL "1") + list(GET LY_PROJECTS 0 project) + file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) + ly_set(LY_DEFAULT_PROJECT_PATH ${full_directory_path}) +endif() + ly_set(LY_PROJECTS_FOLDER_NAME ${LY_PROJECTS_FOLDER_NAME}) From 8a079da914ceadb07846d66230dd031a3b8cccc6 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Sat, 5 Jun 2021 00:04:26 +0200 Subject: [PATCH 114/153] GemCatalog: Gem cart widget and overlay window * [LYN-4174] Added icons for gem catalog summary cart * [LYN-4174] Gem Catalog: Text eliding for too long gem names and creators * [LYN-4174] Gem catalog: Resetting filters when re-initializing for another project * [LYN-4174] Gem Catalog: Fixed a bug with filters being applied/remembered after leaving gem catalog and coming back editing another project * [LYN-4174] GemCatalog: Gem cart widget and overlay window * Added cart button with dynamic label to display the number of gems to be enabled/disabled and a arrow down button to indicate some sort of pop-up/overlay window will appear on click. * Overlay gem tags update dynamically while the dialog is open based on the gem model. * Moved some styling from C++ to the style sheet. --- .../Resources/CarrotArrowDown.svg | 3 + .../Resources/ProjectManager.qrc | 3 + .../Resources/ProjectManager.qss | 40 ++- .../ProjectManager/Resources/Summary.svg | 3 + .../ProjectManager/Resources/WindowClose.svg | 4 + .../GemCatalog/GemCatalogHeaderWidget.cpp | 235 +++++++++++++++++- .../GemCatalog/GemCatalogHeaderWidget.h | 64 ++++- .../Source/GemCatalog/GemCatalogScreen.cpp | 8 +- .../Source/GemCatalog/GemCatalogScreen.h | 2 + .../Source/GemCatalog/GemItemDelegate.cpp | 8 +- .../GemCatalog/GemSortFilterProxyModel.cpp | 11 + .../GemCatalog/GemSortFilterProxyModel.h | 1 + 12 files changed, 350 insertions(+), 32 deletions(-) create mode 100644 Code/Tools/ProjectManager/Resources/CarrotArrowDown.svg create mode 100644 Code/Tools/ProjectManager/Resources/Summary.svg create mode 100644 Code/Tools/ProjectManager/Resources/WindowClose.svg diff --git a/Code/Tools/ProjectManager/Resources/CarrotArrowDown.svg b/Code/Tools/ProjectManager/Resources/CarrotArrowDown.svg new file mode 100644 index 0000000000..73545968d5 --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/CarrotArrowDown.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc index 04d5e98a10..62b7d23e9c 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc @@ -26,5 +26,8 @@ Backgrounds/FirstTimeBackgroundImage.jpg ArrowDownLine.svg ArrowUpLine.svg + CarrotArrowDown.svg + Summary.svg + WindowClose.svg diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 224574f522..6fd4086c58 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -115,7 +115,7 @@ QTabBar::tab:pressed /************** General (Modal windows) **************/ #header { - background-color:#111111; + background-color:#111111; min-height:80px; max-height:80px; } @@ -172,8 +172,8 @@ QTabBar::tab:pressed #footer > QPushButton { qproperty-flat: true; - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #0095f2, stop: 1.0 #1e70eb); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #0095f2, stop: 1.0 #1e70eb); border-radius: 3px; min-height: 28px; max-height: 28px; @@ -181,26 +181,26 @@ QTabBar::tab:pressed margin-right:30px; } #footer > QPushButton:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #10A5f2, stop: 1.0 #2e80eb); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #10A5f2, stop: 1.0 #2e80eb); } #footer > QPushButton:pressed { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #0085e2, stop: 1.0 #0e60db); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #0085e2, stop: 1.0 #0e60db); } #footer > QPushButton[secondary="true"] { margin-right: 10px; - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #888888, stop: 1.0 #555555); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #888888, stop: 1.0 #555555); } #footer > QPushButton[secondary="true"]:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #999999, stop: 1.0 #666666); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #999999, stop: 1.0 #666666); } #footer > QPushButton[secondary="true"]:pressed { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, - stop: 0 #555555, stop: 1.0 #777777); + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #555555, stop: 1.0 #777777); } /************** Project Settings **************/ @@ -356,6 +356,20 @@ QTabBar::tab:pressed font-size: 18px; } +#GemCatalogCart { + background-color: #555555; +} + +#GemCatalogCartCountLabel { + font-size: 12px; + background-color: #4285F4; + border-radius: 3px; +} + +#GemCatalogCartOverlaySectionLabel { + font-weight: 600; +} + /************** Gem Catalog (Inspector) **************/ #GemCatalogInspector { diff --git a/Code/Tools/ProjectManager/Resources/Summary.svg b/Code/Tools/ProjectManager/Resources/Summary.svg new file mode 100644 index 0000000000..fe26718aff --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/Summary.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Tools/ProjectManager/Resources/WindowClose.svg b/Code/Tools/ProjectManager/Resources/WindowClose.svg new file mode 100644 index 0000000000..0485ff95cd --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/WindowClose.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 6402121e4a..a98135d3e6 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -10,24 +10,229 @@ * */ -#include #include #include +#include #include +#include +#include namespace O3DE::ProjectManager { - GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent) + CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, QWidget* parent) + : QWidget(parent) + , m_gemModel(gemModel) + { + setObjectName("GemCatalogCart"); + + m_layout = new QVBoxLayout(); + m_layout->setSpacing(0); + m_layout->setMargin(0); + m_layout->setAlignment(Qt::AlignTop); + setLayout(m_layout); + + QHBoxLayout* hLayout = new QHBoxLayout(); + + QPushButton* closeButton = new QPushButton(); + closeButton->setFlat(true); + closeButton->setFocusPolicy(Qt::NoFocus); + closeButton->setIcon(QIcon(":/WindowClose.svg")); + connect(closeButton, &QPushButton::clicked, this, [=] + { + deleteLater(); + }); + hLayout->addSpacerItem(new QSpacerItem(10, 0, QSizePolicy::Expanding)); + hLayout->addWidget(closeButton); + m_layout->addLayout(hLayout); + + // enabled + { + m_enabledWidget = new QWidget(); + m_enabledWidget->setFixedWidth(s_width); + m_layout->addWidget(m_enabledWidget); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->setAlignment(Qt::AlignTop); + m_enabledWidget->setLayout(layout); + + m_enabledLabel = new QLabel(); + m_enabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); + layout->addWidget(m_enabledLabel); + m_enabledTagContainer = new TagContainerWidget(); + layout->addWidget(m_enabledTagContainer); + } + + // disabled + { + m_disabledWidget = new QWidget(); + m_disabledWidget->setFixedWidth(s_width); + m_layout->addWidget(m_disabledWidget); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->setAlignment(Qt::AlignTop); + m_disabledWidget->setLayout(layout); + + m_disabledLabel = new QLabel(); + m_disabledLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); + layout->addWidget(m_disabledLabel); + m_disabledTagContainer = new TagContainerWidget(); + layout->addWidget(m_disabledTagContainer); + } + + setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); + + Update(); + connect(gemModel, &GemModel::dataChanged, this, [=] + { + Update(); + }); + } + + void CartOverlayWidget::Update() + { + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); + if (toBeAdded.isEmpty()) + { + m_enabledWidget->hide(); + } + else + { + m_enabledTagContainer->Update(ConvertFromModelIndices(toBeAdded)); + m_enabledLabel->setText(QString("%1 %2").arg(QString::number(toBeAdded.size()), tr("Gems to be enabled"))); + m_enabledWidget->show(); + } + + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); + if (toBeRemoved.isEmpty()) + { + m_disabledWidget->hide(); + } + else + { + m_disabledTagContainer->Update(ConvertFromModelIndices(toBeRemoved)); + m_disabledLabel->setText(QString("%1 %2").arg(QString::number(toBeRemoved.size()), tr("Gems to be disabled"))); + m_disabledWidget->show(); + } + } + + QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const + { + QStringList gemNames; + gemNames.reserve(gems.size()); + for (const QModelIndex& modelIndex : gems) + { + gemNames.push_back(GemModel::GetName(modelIndex)); + } + return gemNames; + } + + CartButton::CartButton(GemModel* gemModel, QWidget* parent) + : QWidget(parent) + , m_gemModel(gemModel) + { + m_layout = new QHBoxLayout(); + m_layout->setMargin(0); + setLayout(m_layout); + + QPushButton* iconButton = new QPushButton(); + iconButton->setFlat(true); + iconButton->setFocusPolicy(Qt::NoFocus); + iconButton->setIcon(QIcon(":/Summary.svg")); + iconButton->setFixedSize(s_iconSize, s_iconSize); + connect(iconButton, &QPushButton::clicked, this, &CartButton::ShowOverlay); + m_layout->addWidget(iconButton); + + m_countLabel = new QLabel(); + m_countLabel->setObjectName("GemCatalogCartCountLabel"); + m_countLabel->setFixedHeight(s_iconSize - 1); // Compensate for the empty icon space by using a slightly smaller label height. + m_layout->addWidget(m_countLabel); + + m_dropDownButton = new QPushButton(); + m_dropDownButton->setFlat(true); + m_dropDownButton->setFocusPolicy(Qt::NoFocus); + m_dropDownButton->setIcon(QIcon(":/CarrotArrowDown.svg")); + m_dropDownButton->setFixedSize(s_arrowDownIconSize, s_arrowDownIconSize); + connect(m_dropDownButton, &QPushButton::clicked, this, &CartButton::ShowOverlay); + m_layout->addWidget(m_dropDownButton); + + // Adjust the label text whenever the model gets updated. + connect(gemModel, &GemModel::dataChanged, [=] + { + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); + + const int count = toBeAdded.size() + toBeRemoved.size(); + m_countLabel->setText(QString::number(count)); + + m_dropDownButton->setVisible(!toBeAdded.isEmpty() || !toBeRemoved.isEmpty()); + + // Automatically close the overlay window in case there are no gems to be enabled or disabled anymore. + if (m_cartOverlay && toBeAdded.isEmpty() && toBeRemoved.isEmpty()) + { + m_cartOverlay->deleteLater(); + m_cartOverlay = nullptr; + } + }); + } + + void CartButton::mousePressEvent([[maybe_unused]] QMouseEvent* event) + { + ShowOverlay(); + } + + void CartButton::ShowOverlay() + { + const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); + const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); + if (toBeAdded.isEmpty() && toBeRemoved.isEmpty()) + { + return; + } + + if (m_cartOverlay) + { + // Directly delete the former overlay before creating the new one. + // Don't use deleteLater() here. This might overwrite the new overlay pointer + // depending on the event queue. + delete m_cartOverlay; + } + + m_cartOverlay = new CartOverlayWidget(m_gemModel, this); + connect(m_cartOverlay, &QWidget::destroyed, this, [=] + { + // Reset the overlay pointer on destruction to prevent dangling pointers. + m_cartOverlay = nullptr; + }); + m_cartOverlay->show(); + + const QPoint parentPos = m_dropDownButton->mapToParent(m_dropDownButton->pos()); + const QPoint globalPos = m_dropDownButton->mapToGlobal(m_dropDownButton->pos()); + const QPoint offset(-4, 10); + m_cartOverlay->setGeometry(globalPos.x() - parentPos.x() - m_cartOverlay->width() + width() + offset.x(), + globalPos.y() + offset.y(), + m_cartOverlay->width(), + m_cartOverlay->height()); + } + + CartButton::~CartButton() + { + // Make sure the overlay window is automatically closed in case the gem catalog is destroyed. + if (m_cartOverlay) + { + m_cartOverlay->deleteLater(); + } + } + + GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent) : QFrame(parent) { QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setAlignment(Qt::AlignLeft); - hLayout->setMargin(0); + hLayout->setContentsMargins(10, 7, 10, 7); setLayout(hLayout); setObjectName("GemCatalogHeaderWidget"); - - hLayout->addSpacing(7); + setFixedHeight(s_height); QLabel* titleLabel = new QLabel(tr("Gem Catalog")); titleLabel->setObjectName("GemCatalogTitle"); @@ -35,17 +240,23 @@ namespace O3DE::ProjectManager hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); - AzQtComponents::SearchLineEdit* filterLineEdit = new AzQtComponents::SearchLineEdit(); - filterLineEdit->setStyleSheet("background-color: #DDDDDD;"); - connect(filterLineEdit, &QLineEdit::textChanged, this, [=](const QString& text) + m_filterLineEdit = new AzQtComponents::SearchLineEdit(); + m_filterLineEdit->setStyleSheet("background-color: #DDDDDD;"); + connect(m_filterLineEdit, &QLineEdit::textChanged, this, [=](const QString& text) { filterProxyModel->SetSearchString(text); }); - hLayout->addWidget(filterLineEdit); + hLayout->addWidget(m_filterLineEdit); hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); - hLayout->addSpacerItem(new QSpacerItem(140, 0, QSizePolicy::Fixed)); - - setFixedHeight(60); + hLayout->addSpacerItem(new QSpacerItem(75, 0, QSizePolicy::Fixed)); + + CartButton* cartButton = new CartButton(gemModel); + hLayout->addWidget(cartButton); + } + + void GemCatalogHeaderWidget::ReinitForProject() + { + m_filterLineEdit->setText({}); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 3e065edd8f..bef7555618 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -13,19 +13,81 @@ #pragma once #if !defined(Q_MOC_RUN) +#include +#include #include +#include #include +#include +#include +#include +#include #endif namespace O3DE::ProjectManager { + class CartOverlayWidget + : public QWidget + { + Q_OBJECT // AUTOMOC + + public: + CartOverlayWidget(GemModel* gemModel, QWidget* parent = nullptr); + void Update(); + + private: + QStringList ConvertFromModelIndices(const QVector& gems) const; + + QVBoxLayout* m_layout = nullptr; + GemModel* m_gemModel = nullptr; + + QWidget* m_enabledWidget = nullptr; + QLabel* m_enabledLabel = nullptr; + TagContainerWidget* m_enabledTagContainer = nullptr; + + QWidget* m_disabledWidget = nullptr; + QLabel* m_disabledLabel = nullptr; + TagContainerWidget* m_disabledTagContainer = nullptr; + + inline constexpr static int s_width = 240; + }; + + class CartButton + : public QWidget + { + Q_OBJECT // AUTOMOC + + public: + CartButton(GemModel* gemModel, QWidget* parent = nullptr); + ~CartButton(); + void ShowOverlay(); + + private: + void mousePressEvent(QMouseEvent* event) override; + + GemModel* m_gemModel = nullptr; + QHBoxLayout* m_layout = nullptr; + QLabel* m_countLabel = nullptr; + QPushButton* m_dropDownButton = nullptr; + CartOverlayWidget* m_cartOverlay = nullptr; + + inline constexpr static int s_iconSize = 24; + inline constexpr static int s_arrowDownIconSize = 8; + }; + class GemCatalogHeaderWidget : public QFrame { Q_OBJECT // AUTOMOC public: - explicit GemCatalogHeaderWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr); + explicit GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr); ~GemCatalogHeaderWidget() = default; + + void ReinitForProject(); + + private: + AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr; + inline constexpr static int s_height = 60; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index aa36c1b0ab..4424767c0b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -35,8 +34,8 @@ namespace O3DE::ProjectManager vLayout->setSpacing(0); setLayout(vLayout); - GemCatalogHeaderWidget* headerWidget = new GemCatalogHeaderWidget(m_proxModel); - vLayout->addWidget(headerWidget); + m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel); + vLayout->addWidget(m_headerWidget); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); @@ -77,10 +76,11 @@ namespace O3DE::ProjectManager m_filterWidget->deleteLater(); } + m_proxModel->ResetFilters(); m_filterWidget = new GemFilterWidget(m_proxModel); m_filterWidgetLayout->addWidget(m_filterWidget); - m_proxModel->InvalidateFilter(); + m_headerWidget->ReinitForProject(); // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 0847d9b74e..f5092e837a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -14,6 +14,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include #include @@ -40,6 +41,7 @@ namespace O3DE::ProjectManager GemListView* m_gemListView = nullptr; GemInspector* m_gemInspector = nullptr; GemModel* m_gemModel = nullptr; + GemCatalogHeaderWidget* m_headerWidget = nullptr; GemSortFilterProxyModel* m_proxModel = nullptr; QVBoxLayout* m_filterWidgetLayout = nullptr; GemFilterWidget* m_filterWidget = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 0fc0d89fcb..8aa68fb7a2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -53,6 +53,7 @@ namespace O3DE::ProjectManager QFont standardFont(options.font); standardFont.setPixelSize(s_fontSize); + QFontMetrics standardFontMetrics(standardFont); painter->save(); painter->setClipping(true); @@ -78,8 +79,10 @@ namespace O3DE::ProjectManager } // Gem name - const QString gemName = GemModel::GetName(modelIndex); + QString gemName = GemModel::GetName(modelIndex); QFont gemNameFont(options.font); + const int firstColumnMaxTextWidth = s_summaryStartX - 30; + gemName = QFontMetrics(gemNameFont).elidedText(gemName, Qt::TextElideMode::ElideRight, firstColumnMaxTextWidth); gemNameFont.setPixelSize(s_gemNameFontSize); gemNameFont.setBold(true); QRect gemNameRect = GetTextRect(gemNameFont, gemName, s_gemNameFontSize); @@ -90,7 +93,8 @@ namespace O3DE::ProjectManager painter->drawText(gemNameRect, Qt::TextSingleLine, gemName); // Gem creator - const QString gemCreator = GemModel::GetCreator(modelIndex); + QString gemCreator = GemModel::GetCreator(modelIndex); + gemCreator = standardFontMetrics.elidedText(gemCreator, Qt::TextElideMode::ElideRight, firstColumnMaxTextWidth); QRect gemCreatorRect = GetTextRect(standardFont, gemCreator, s_fontSize); gemCreatorRect.moveTo(contentRect.left(), contentRect.top() + gemNameRect.height()); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp index 33936f417e..d8f41c077e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -130,4 +130,15 @@ namespace O3DE::ProjectManager invalidate(); emit OnInvalidated(); } + + void GemSortFilterProxyModel::ResetFilters() + { + m_searchString.clear(); + m_gemOriginFilter = {}; + m_platformFilter = {}; + m_typeFilter = {}; + m_featureFilter = {}; + + InvalidateFilter(); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h index e5554c020c..f24a724ecf 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h @@ -51,6 +51,7 @@ namespace O3DE::ProjectManager void SetFeatures(const QSet& features) { m_featureFilter = features; InvalidateFilter(); } void InvalidateFilter(); + void ResetFilters(); signals: void OnInvalidated(); From dbdf97069003a3db5cbded1f6b4b0cd4509aa230 Mon Sep 17 00:00:00 2001 From: gallowj Date: Fri, 4 Jun 2021 17:09:44 -0500 Subject: [PATCH 115/153] Atom15729 Fixed broken materials --- .../Assets/Materials/baseboards.material | 3 -- .../Lighthead_lightfacingemissive.material | 9 ---- .../PlayfulTeapot_playfulteapot.material | 12 ----- .../Assets/Materials/Copper/copper.material | 5 --- .../Assets/Materials/Plaster/plaster.material | 11 ----- .../Materials/Plastic_01/plastic_01.material | 11 ----- .../objects/sponza_mat_ceiling.material | 44 +++---------------- .../Assets/objects/sponza_mat_chain.material | 27 +++--------- .../Assets/objects/sponza_mat_leaf.material | 19 -------- .../Assets/objects/sponza_mat_lion.material | 35 +++------------ .../objects/sponza_mat_vaseplant.material | 18 -------- 11 files changed, 18 insertions(+), 176 deletions(-) diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material index f75490c2ad..dee6ded191 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material @@ -37,9 +37,6 @@ "factor": 0.4343433976173401, "textureMap": "Materials/Bricks038_8K/Bricks038_8K_Roughness.png", "useTexture": false - }, - "subsurfaceScattering": { - "useThicknessMap": false } } } diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/Lighthead_lightfacingemissive.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/Lighthead_lightfacingemissive.material index 21cb12a82c..ddc298a08b 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/Lighthead_lightfacingemissive.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/Lighthead_lightfacingemissive.material @@ -18,15 +18,6 @@ }, "opacity": { "factor": 1.0 - }, - "subsurfaceScattering": { - "enableSubsurfaceScattering": true, - "quality": 1.0, - "scatterDistance": 2.626262664794922, - "subsurfaceScatterFactor": 1.0, - "thickness": 0.1414141058921814, - "transmissionMode": "ThinObject", - "transmissionScale": 1.8181817531585694 } } } diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material index b46dd709b1..27540c587e 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material @@ -31,18 +31,6 @@ }, "roughness": { "factor": 0.0 - }, - "subsurfaceScattering": { - "enableSubsurfaceScattering": true, - "quality": 1.0, - "scatterColor": [ - 0.045288778841495517, - 0.24347294867038728, - 0.2060578316450119, - 1.0 - ], - "scatterDistance": 4.040403842926025, - "subsurfaceScatterFactor": 0.5 } } } diff --git a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Copper/copper.material b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Copper/copper.material index 4489e12c4d..80b7ea29f3 100644 --- a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Copper/copper.material +++ b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Copper/copper.material @@ -20,11 +20,6 @@ }, "roughness": { "factor": 0.20202019810676576 - }, - "subsurfaceScattering": { - "quality": 0.329292893409729, - "scatterDistance": 6.666666507720947, - "subsurfaceScatterFactor": 0.9595959782600403 } } } diff --git a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plaster/plaster.material b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plaster/plaster.material index 3121fdac24..cdf76f612d 100644 --- a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plaster/plaster.material +++ b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plaster/plaster.material @@ -28,17 +28,6 @@ }, "specularF0": { "factor": 1.0 - }, - "subsurfaceScattering": { - "quality": 0.9838383793830872, - "scatterColor": [ - 0.143602654337883, - 0.012634470127522946, - 0.0005798428319394589, - 1.0 - ], - "scatterDistance": 18.383838653564454, - "subsurfaceScatterFactor": 0.1414141058921814 } } } diff --git a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plastic_01/plastic_01.material b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plastic_01/plastic_01.material index e953d04238..227017e1ab 100644 --- a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plastic_01/plastic_01.material +++ b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/Plastic_01/plastic_01.material @@ -25,17 +25,6 @@ }, "specularF0": { "factor": 1.0 - }, - "subsurfaceScattering": { - "quality": 0.9838383793830872, - "scatterColor": [ - 0.143602654337883, - 0.012634470127522946, - 0.0005798428319394589, - 1.0 - ], - "scatterDistance": 18.383838653564454, - "subsurfaceScatterFactor": 0.1414141058921814 } } } diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material index 95d08d398b..88730c9556 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material @@ -4,20 +4,15 @@ "parentMaterial": "", "propertyLayoutVersion": 3, "properties": { - "occlusion": { - "diffuseTextureMap": "Textures/ceiling_1k_ao.png" - }, "baseColor": { - "textureBlendMode": "Lerp", + "color": [ + 0.800000011920929, + 0.800000011920929, + 0.800000011920929, + 1.0 + ], "textureMap": "Textures/ceiling_1k_basecolor.png" }, - "clearCoat": { - "enable": true, - "factor": 0.5, - "influenceMap": "Textures/ceiling_1k_ao.png", - "normalMap": "Textures/ceiling_1k_normal.png", - "roughness": 0.30000001192092898 - }, "emissive": { "color": [ 0.0, @@ -26,33 +21,8 @@ 1.0 ] }, - "general": { - "applySpecularAA": true - }, - "irradiance": { - "color": [ - 1.0, - 0.7591058015823364, - 0.43776607513427737, - 1.0 - ] - }, - "normal": { - "textureMap": "Textures/ceiling_1k_normal.png" - }, "opacity": { "factor": 1.0 - }, - "parallax": { - "algorithm": "ContactRefinement", - "factor": 0.019999999552965165, - "pdo": true, - "quality": "Medium", - "textureMap": "Textures/ceiling_1k_height.png", - "useTexture": false - }, - "roughness": { - "textureMap": "Textures/ceiling_1k_roughness.png" } } -} +} \ No newline at end of file diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_chain.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_chain.material index 223bd0a24f..1ed442a9e0 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_chain.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_chain.material @@ -13,31 +13,16 @@ ], "textureMap": "Textures/chain_basecolor.png" }, - "general": { - "applySpecularAA": true - }, - "irradiance": { + "emissive": { "color": [ - 0.4891279339790344, - 0.7931944727897644, - 1.0, + 0.0, + 0.0, + 0.0, 1.0 ] }, - "metallic": { - "textureMap": "Textures/chain_alpha.png" - }, - "normal": { - "textureMap": "Textures/chain_normal.jpg" - }, "opacity": { - "alphaSource": "Split", - "factor": 0.30000001192092898, - "mode": "Cutout", - "textureMap": "Textures/chain_alpha.png" - }, - "roughness": { - "factor": 0.4000000059604645 + "factor": 1.0 } } -} +} \ No newline at end of file diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material index ac326ae935..c95d0a662b 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material @@ -47,25 +47,6 @@ }, "roughness": { "textureMap": "Textures/thorn_roughness.png" - }, - "subsurfaceScattering": { - "enableSubsurfaceScattering": true, - "quality": 1.0, - "scatterColor": [ - 0.28143739700317385, - 1.0, - 0.13000686466693879, - 1.0 - ], - "scatterDistance": 1.0, - "thickness": 0.10000000149011612, - "transmissionMode": "ThinObject", - "transmissionTint": [ - 0.07225146889686585, - 0.16981765627861024, - 0.04444953054189682, - 1.0 - ] } } } diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material index b1f78aa33f..08eb920607 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material @@ -4,9 +4,6 @@ "parentMaterial": "", "propertyLayoutVersion": 3, "properties": { - "occlusion": { - "diffuseTextureMap": "Textures/lion_1k_ao.png" - }, "baseColor": { "color": [ 0.800000011920929, @@ -16,38 +13,16 @@ ], "textureMap": "Textures/lion_1k_basecolor.png" }, - "general": { - "applySpecularAA": true - }, - "irradiance": { + "emissive": { "color": [ - 1.0, - 0.7364919781684876, - 0.3672388792037964, + 0.0, + 0.0, + 0.0, 1.0 ] }, - "metallic": { - "textureMap": "Textures/lion_1k_metallic.png" - }, - "normal": { - "textureMap": "Textures/lion_1k_normal.jpg" - }, "opacity": { "factor": 1.0 - }, - "parallax": { - "algorithm": "ContactRefinement", - "factor": 0.009999999776482582, - "pdo": true, - "quality": "Ultra", - "textureMap": "Textures/lion_1k_height.png" - }, - "roughness": { - "textureMap": "Textures/lion_1k_roughness.png" - }, - "specularF0": { - "enableMultiScatterCompensation": true } } -} +} \ No newline at end of file diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseplant.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseplant.material index 37d9e2c01c..290ddc81a6 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseplant.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseplant.material @@ -28,24 +28,6 @@ "doubleSided": true, "factor": 0.28999999165534975, "mode": "Cutout" - }, - "subsurfaceScattering": { - "enableSubsurfaceScattering": true, - "quality": 1.0, - "scatterColor": [ - 0.07421988248825073, - 0.10223544389009476, - 0.0, - 1.0 - ], - "subsurfaceScatterFactor": 0.0, - "transmissionMode": "ThinObject", - "transmissionTint": [ - 0.33716335892677309, - 0.4620737135410309, - 0.0, - 1.0 - ] } } } From e71a4656bc1a3a304ee124c426d0936dafc22a38 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:10:20 -0700 Subject: [PATCH 116/153] SPEC-2513 Fixes to enable w4450 (#1145) * Fix for w4457 * Nothing to fix, seems we deleted all the code that was causing this offense --- cmake/Platform/Common/MSVC/Configurations_msvc.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 357d578c44..d0e4d9ed73 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -72,7 +72,6 @@ ly_append_configurations_options( /wd4366 # the result of unary operator may be unaligned /wd4389 # comparison, signed/unsigned mismatch /wd4436 # the result of unary operator may be unaligned - /wd4450 # declaration hides global declaration # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From cf35585bc0d50e6e09c6e712bdb66351cf40fc94 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:25:57 -0700 Subject: [PATCH 117/153] Making incremental linking off by default (#1154) --- cmake/Platform/Common/MSVC/Configurations_msvc.cmake | 2 +- scripts/build/Platform/Windows/build_config.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index d0e4d9ed73..8c22677f91 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -126,7 +126,7 @@ ly_append_configurations_options( /INCREMENTAL:NO ) -set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG TRUE CACHE BOOL "Indicates if incremental linking is used in debug configurations (default = TRUE)") +set(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG FALSE CACHE BOOL "Indicates if incremental linking is used in debug configurations (default = FALSE)") if(LY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG) ly_append_configurations_options( COMPILATION_DEBUG diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index fc4668de0a..552ef2c6fd 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -87,7 +87,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -101,7 +101,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", From 1396110f6d0edc8795ae7a439945b399b3684e5a Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 15:46:19 -0700 Subject: [PATCH 118/153] Preventing builds from cleaning on each step (#1151) --- scripts/build/Jenkins/Jenkinsfile | 14 +++++++------- scripts/build/Platform/Linux/build_linux.sh | 1 - scripts/build/Platform/Mac/build_mac.sh | 1 - scripts/build/Platform/Windows/build_windows.cmd | 1 - 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 2f6be2b060..3cf7d92ba6 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -313,13 +313,13 @@ def PreBuildCommonSteps(Map pipelineConfig, String repositoryName, String projec script: 'python/get_python.bat' } - if(env.CLEAN_OUTPUT_DIRECTORY?.toBoolean() || env.CLEAN_ASSETS?.toBoolean()) { - def command = "${pipelineConfig.PYTHON_DIR}/python" - if(env.IS_UNIX) command += '.sh' - else command += '.cmd' - command += " -u ${pipelineConfig.BUILD_ENTRY_POINT} --platform ${platform} --type clean" - palSh(command, "Running ${platform} clean") - } + // Always run the clean step, the scripts detect what variables were set, but it also cleans if + // the NODE_LABEL has changed + def command = "${pipelineConfig.PYTHON_DIR}/python" + if(env.IS_UNIX) command += '.sh' + else command += '.cmd' + command += " -u ${pipelineConfig.BUILD_ENTRY_POINT} --platform ${platform} --type clean" + palSh(command, "Running ${platform} clean") } } diff --git a/scripts/build/Platform/Linux/build_linux.sh b/scripts/build/Platform/Linux/build_linux.sh index ef1b1dcb96..f88d3ab116 100755 --- a/scripts/build/Platform/Linux/build_linux.sh +++ b/scripts/build/Platform/Linux/build_linux.sh @@ -14,7 +14,6 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_linux.sh -source $BASEDIR/clean_linux.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} diff --git a/scripts/build/Platform/Mac/build_mac.sh b/scripts/build/Platform/Mac/build_mac.sh index 4a61f97fe4..473a968d98 100755 --- a/scripts/build/Platform/Mac/build_mac.sh +++ b/scripts/build/Platform/Mac/build_mac.sh @@ -14,7 +14,6 @@ set -o errexit # exit on the first failure encountered BASEDIR=$(dirname "$0") source $BASEDIR/env_mac.sh -source $BASEDIR/clean_mac.sh mkdir -p ${OUTPUT_DIRECTORY} SOURCE_DIRECTORY=${PWD} diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 474c1720df..4dcd12d008 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -13,7 +13,6 @@ REM SETLOCAL EnableDelayedExpansion CALL %~dp0env_windows.cmd -CALL %~dp0clean_windows.cmd IF NOT EXIST "%OUTPUT_DIRECTORY%" ( MKDIR %OUTPUT_DIRECTORY%. From 74f474aae2084c0489fd9dfa8b5025970b197e03 Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Fri, 4 Jun 2021 18:02:09 -0500 Subject: [PATCH 119/153] Add unit tests for the ViewportScreen ndc <-> worldspace utility functions (#1149) Add ScreenNdcToWorld function to enable round trip testing. --- .../AzFramework/Viewport/ViewportScreen.cpp | 17 +++- .../AzFramework/Viewport/ViewportScreen.h | 8 +- .../Tests/Viewport/ViewportScreenTests.cpp | 87 ++++++++++++++++++- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp index 5d2d02a398..8283e0b1f2 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp @@ -128,12 +128,12 @@ namespace AzFramework worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize); } - AZ::Vector3 ScreenToWorld( - const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView, - const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize) + AZ::Vector3 ScreenNDCToWorld( + const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView, + const AZ::Matrix4x4& inverseCameraProjection) { // convert screen space coordinates from <0, 1> to <-1,1> range - const auto ndcPosition = NDCFromScreenPoint(screenPosition, viewportSize) * 2.0f - AZ::Vector2::CreateOne(); + const auto ndcPosition = normalizedScreenPosition * 2.0f - AZ::Vector2::CreateOne(); // transform ndc space position to clip space const auto clipSpacePosition = inverseCameraProjection * Vector2ToVector4(ndcPosition, -1.0f, 1.0f); @@ -145,6 +145,15 @@ namespace AzFramework return worldPosition; } + AZ::Vector3 ScreenToWorld( + const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView, + const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize) + { + const auto normalizedScreenPosition = NDCFromScreenPoint(screenPosition, viewportSize); + + return ScreenNDCToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection); + } + AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState) { return ScreenToWorld( diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h index a2c650465f..844f52b565 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h @@ -42,7 +42,7 @@ namespace AzFramework const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection, const AZ::Vector2& viewportSize); - //! Unprojects a position in screen space to world space. + //! Unprojects a position in screen space pixel coordinates to world space. //! Note: The position returned will be on the near clip plane of the camera in world space. AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState); @@ -52,6 +52,12 @@ namespace AzFramework const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize); + //! Unprojects a position in screen space normalized device coordinates to world space. + //! Note: The position returned will be on the near clip plane of the camera in world space. + AZ::Vector3 ScreenNDCToWorld( + const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView, + const AZ::Matrix4x4& inverseCameraProjection); + //! Returns the camera projection for the current camera state. AZ::Matrix4x4 CameraProjection(const CameraState& cameraState); diff --git a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp index 18462bc97b..d82c7ec425 100644 --- a/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Viewport/ViewportScreenTests.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,15 @@ namespace UnitTest { + // transform a point from normalized device coordinates to world space, and then from world space back to normalized device coordinates + AZ::Vector2 ScreenNDCToWorldToScreenNDC( + const AZ::Vector2& ndcPoint, const AzFramework::CameraState& cameraState) + { + const auto worldResult = AzFramework::ScreenNDCToWorld(ndcPoint, InverseCameraView(cameraState), InverseCameraProjection(cameraState)); + const auto ndcResult = AzFramework::WorldToScreenNDC(worldResult, CameraView(cameraState), CameraProjection(cameraState)); + return AZ::Vector3ToVector2(ndcResult); + } + // transform a point from screen space to world space, and then from world space back to screen space AzFramework::ScreenPoint ScreenToWorldToScreen( const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState) @@ -30,7 +40,8 @@ namespace UnitTest const auto worldResult = AzFramework::ScreenToWorld(screenPoint, cameraState); return AzFramework::WorldToScreen(worldResult, cameraState); } - + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // ScreenPoint tests TEST(ViewportScreen, WorldToScreenAndScreenToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin) { using AzFramework::ScreenPoint; @@ -38,8 +49,6 @@ namespace UnitTest const auto screenDimensions = AZ::Vector2(800.0f, 600.0f); const auto cameraPosition = AZ::Vector3::CreateAxisY(-10.0f); - // note: nearClip is 0.1 - the world space value returned will be aligned to the near clip - // plane of the camera so use that to confirm the mapping to/from is correct const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions); { const auto expectedScreenPoint = ScreenPoint{600, 450}; @@ -81,6 +90,8 @@ namespace UnitTest EXPECT_EQ(resultScreenPoint, expectedScreenPoint); } + // note: nearClip is 0.1 - the world space value returned will be aligned to the near clip + // plane of the camera so use that to confirm the mapping to/from is correct TEST(ViewportScreen, ScreenToWorldReturnsPositionOnNearClipPlaneInWorldSpace) { using AzFramework::ScreenPoint; @@ -94,7 +105,75 @@ namespace UnitTest const auto worldResult = AzFramework::ScreenToWorld(ScreenPoint{400, 300}, cameraState); EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f))); } + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // NDC tests + TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueIdentityCameraOffsetFromOrigin) + { + using NdcPoint = AZ::Vector2; + + const auto screenDimensions = AZ::Vector2(800.0f, 600.0f); + const auto cameraPosition = AZ::Vector3::CreateAxisY(-10.0f); + const auto cameraState = AzFramework::CreateIdentityDefaultCamera(cameraPosition, screenDimensions); + { + const auto expectedNdcPoint = NdcPoint{0.75f, 0.75f}; + const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState); + EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint)); + } + + { + const auto expectedNdcPoint = NdcPoint{0.5f, 0.5f}; + const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState); + EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint)); + } + + { + const auto expectedNdcPoint = NdcPoint{0.0f, 0.0f}; + const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState); + EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint)); + } + + { + const auto expectedNdcPoint = NdcPoint{1.0f, 1.0f}; + const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState); + EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint)); + } + } + + TEST(ViewportScreen, WorldToScreenNDCAndScreenNDCToWorldReturnsTheSameValueOrientatedCamera) + { + using NdcPoint = AZ::Vector2; + + const auto screenDimensions = AZ::Vector2(800.0f, 600.0f); + const auto cameraTransform = + AZ::Transform::CreateRotationX(AZ::DegToRad(45.0f)) * AZ::Transform::CreateRotationZ(AZ::DegToRad(90.0f)); + + const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions); + + const auto expectedNdcPoint = NdcPoint{0.25f, 0.5f}; + const auto resultNdcPoint = ScreenNDCToWorldToScreenNDC(expectedNdcPoint, cameraState); + EXPECT_THAT(resultNdcPoint, IsClose(expectedNdcPoint)); + } + + // note: nearClip is 0.1 - the world space value returned will be aligned to the near clip + // plane of the camera so use that to confirm the mapping to/from is correct + TEST(ViewportScreen, ScreenNDCToWorldReturnsPositionOnNearClipPlaneInWorldSpace) + { + using NdcPoint = AZ::Vector2; + + const auto screenDimensions = AZ::Vector2(800.0f, 600.0f); + const auto cameraTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 0.0f, 0.0f)) * + AZ::Transform::CreateRotationZ(AZ::DegToRad(-90.0f)); + + const auto cameraState = AzFramework::CreateDefaultCamera(cameraTransform, screenDimensions); + + const auto worldResult = AzFramework::ScreenNDCToWorld(NdcPoint{0.5f, 0.5f}, InverseCameraView(cameraState), InverseCameraProjection(cameraState)); + EXPECT_THAT(worldResult, IsClose(AZ::Vector3(10.1f, 0.0f, 0.0f))); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // ScreenVector tests TEST(ViewportScreen, SubstractingScreenPointGivesScreenVector) { using AzFramework::ScreenPoint; @@ -220,6 +299,8 @@ namespace UnitTest EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(12, 15)), 19.20937f, 0.001f); } + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // Other tests TEST(ViewportScreen, CanGetCameraTransformFromCameraViewAndBack) { const auto screenDimensions = AZ::Vector2(1024.0f, 768.0f); From 6ee58b7b641ea9b7bd8727217920e0f9477bc664 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Fri, 4 Jun 2021 16:09:37 -0700 Subject: [PATCH 120/153] Fix overrides for array in editor setreg. Remove the test overrides. --- Registry/Platform/Mac/streamer.editor.setreg | 5 ++++ Registry/Platform/Mac/streamer.test.setreg | 24 -------------------- 2 files changed, 5 insertions(+), 24 deletions(-) delete mode 100644 Registry/Platform/Mac/streamer.test.setreg diff --git a/Registry/Platform/Mac/streamer.editor.setreg b/Registry/Platform/Mac/streamer.editor.setreg index 85360d128e..dafcfdc9d9 100644 --- a/Registry/Platform/Mac/streamer.editor.setreg +++ b/Registry/Platform/Mac/streamer.editor.setreg @@ -18,6 +18,11 @@ // can have open is set to 256. So we need to set this to a lower value than on PC. // This limit is set by "launchctl limit maxfiles" "MaxFileHandles": 65 + }, + { + "$type": "AzFramework::RemoteStorageDriveConfig", + // The maximum number of file handles that the drive will cache. + "MaxFileHandles": 1024 } ] } diff --git a/Registry/Platform/Mac/streamer.test.setreg b/Registry/Platform/Mac/streamer.test.setreg deleted file mode 100644 index df41b7a350..0000000000 --- a/Registry/Platform/Mac/streamer.test.setreg +++ /dev/null @@ -1,24 +0,0 @@ -{ - "Amazon": - { - "AzCore": - { - "Streamer": - { - "Profiles": - { - "Generic": - { - "Stack": - [ - { - "$type": "AZ::IO::StorageDriveConfig", - "MaxFileHandles": 65 - } - ] - } - } - } - } - } -} \ No newline at end of file From 9b1775427895177c6d0125dd6d6ed6bc95d6c823 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 4 Jun 2021 16:14:25 -0700 Subject: [PATCH 121/153] Project Template details and preview changes --- .../Resources/ArrowBack_Hover.svg | 3 + .../Resources/DefaultTemplate.png | 3 + .../Resources/ProjectManager.qrc | 2 + .../Resources/ProjectManager.qss | 67 ++++++- .../Source/CreateProjectCtrl.cpp | 183 ++++++++++++------ .../ProjectManager/Source/CreateProjectCtrl.h | 36 +++- .../Source/NewProjectSettingsScreen.cpp | 127 ++++++++++-- .../Source/NewProjectSettingsScreen.h | 14 ++ .../Source/ProjectTemplateInfo.h | 1 + .../ProjectManager/Source/PythonBindings.cpp | 9 +- .../Source/TemplateButtonWidget.cpp | 65 +++++++ .../Source/TemplateButtonWidget.h | 37 ++++ .../project_manager_files.cmake | 2 + Templates/DefaultProject/template.json | 5 +- 14 files changed, 464 insertions(+), 90 deletions(-) create mode 100644 Code/Tools/ProjectManager/Resources/ArrowBack_Hover.svg create mode 100644 Code/Tools/ProjectManager/Resources/DefaultTemplate.png create mode 100644 Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp create mode 100644 Code/Tools/ProjectManager/Source/TemplateButtonWidget.h diff --git a/Code/Tools/ProjectManager/Resources/ArrowBack_Hover.svg b/Code/Tools/ProjectManager/Resources/ArrowBack_Hover.svg new file mode 100644 index 0000000000..5b3b14f09a --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/ArrowBack_Hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/Code/Tools/ProjectManager/Resources/DefaultTemplate.png b/Code/Tools/ProjectManager/Resources/DefaultTemplate.png new file mode 100644 index 0000000000..2634c383fc --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/DefaultTemplate.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8358f4dad9878c662b9819b2b346622af691eb45f8eddc28fff79a50650ae6cf +size 2503 diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc index 62b7d23e9c..33acfa9e1b 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc @@ -7,6 +7,7 @@ AddOffset.svg AddOffset_Hover.svg ArrowBack.svg + ArrowBack_Hover.svg build.svg FolderOffset.svg FolderOffset_Hover.svg @@ -18,6 +19,7 @@ Linux.svg macOS.svg DefaultProjectImage.png + DefaultTemplate.png ArrowDownLine.svg ArrowUpLine.svg o3de.svg diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 6fd4086c58..8b7470051c 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -136,11 +136,9 @@ QTabBar::tab:pressed #header QPushButton:focus { border:none; } -#header QPushButton:hover { - background:#333333 url(:/ArrowBack.svg) no-repeat center; -} +#header QPushButton:hover, #header QPushButton:pressed { - background:#222222 url(:/ArrowBack.svg) no-repeat center; + background:transparent url(:/ArrowBack_Hover.svg) no-repeat center; } #headerTitle { @@ -210,9 +208,6 @@ QTabBar::tab:pressed #projectTemplate { margin: 55px 0 0 50px; - max-width: 780px; - min-height:200px; - max-height:200px; } #projectTemplateLabel { font-size:16px; @@ -227,11 +222,67 @@ QTabBar::tab:pressed #projectTemplateDetails { background-color:#444444; - max-width:240px; + max-width:20%; min-width:240px; margin-left:30px; } +#projectTemplateDetails #displayName, +#projectTemplateDetails #includedGemsTitle { + font-size:18px; +} + +#projectTemplateDetails #moreGems { + font-size:14px; + margin-top:20px; +} + +#projectTemplateDetails #includedGemsTitle { + margin-top:5px; + margin-bottom:5px; +} + +#projectTemplateDetails #summary { + padding-bottom:0px; + border-bottom:2px solid #555555; + min-height:80px; + qproperty-alignment: AlignTop; +} + +#projectTemplateDetails #browseCatalog { + margin:5px 0px 15px 0px; +} + +#projectTemplate QPushButton { + qproperty-flat: true; + min-width: 96px; + max-width: 96px; + min-height: 160px; + max-height: 160px; +} +#projectTemplate #templateLabel { + qproperty-alignment: AlignCenter; +} +#projectTemplate QPushButton #templateImage { + border:3px solid transparent; + border-radius: 4px; +} +#projectTemplate QPushButton[Checked="true"] #templateImage { + border:3px solid #1e70eb; +} +#projectTemplate QPushButton[Checked="true"] #templateLabel { + font-weight:bold; +} +#projectTemplate QPushButton:hover { + background-color: #444444; +} +#projectTemplate QPushButton:focus { + outline: none; + border:none; +} + + + #projectSettingsTab::tab-bar { left: 60px; } diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 85e34aeced..4498a6bc82 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -41,24 +42,33 @@ namespace O3DE::ProjectManager m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); - m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); - m_stack->addWidget(new NewProjectSettingsScreen()); - m_gemCatalog = new GemCatalogScreen(); - m_stack->addWidget(m_gemCatalog); + m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding)); + + m_newProjectSettingsScreen = new NewProjectSettingsScreen(this); + m_stack->addWidget(m_newProjectSettingsScreen); + + m_gemCatalogScreen = new GemCatalogScreen(this); + m_stack->addWidget(m_gemCatalogScreen); vLayout->addWidget(m_stack); - QDialogButtonBox* backNextButtons = new QDialogButtonBox(); - backNextButtons->setObjectName("footer"); - vLayout->addWidget(backNextButtons); + QDialogButtonBox* buttons = new QDialogButtonBox(); + buttons->setObjectName("footer"); + vLayout->addWidget(buttons); - m_backButton = backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole); - m_backButton->setProperty("secondary", true); - m_nextButton = backNextButtons->addButton(tr("Next"), QDialogButtonBox::ApplyRole); +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + connect(m_newProjectSettingsScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); - connect(m_backButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandleBackButton); - connect(m_nextButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandleNextButton); + m_secondaryButton = buttons->addButton(tr("Back"), QDialogButtonBox::RejectRole); + m_secondaryButton->setProperty("secondary", true); + m_secondaryButton->setVisible(false); + connect(m_secondaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandleSecondaryButton); Update(); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED + + m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole); + connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton); + setLayout(vLayout); } @@ -80,8 +90,10 @@ namespace O3DE::ProjectManager { if (m_stack->currentIndex() > 0) { - m_stack->setCurrentIndex(m_stack->currentIndex() - 1); - Update(); +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + PreviousScreen(); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED + } else { @@ -89,70 +101,121 @@ namespace O3DE::ProjectManager } } - void CreateProjectCtrl::HandleNextButton() +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + void CreateProjectCtrl::HandleSecondaryButton() { - ScreenWidget* currentScreen = reinterpret_cast(m_stack->currentWidget()); - ProjectManagerScreen screenEnum = currentScreen->GetScreenEnum(); - - if (screenEnum == ProjectManagerScreen::NewProjectSettings) + if (m_stack->currentIndex() > 0) { - auto newProjectScreen = reinterpret_cast(currentScreen); - if (newProjectScreen) - { - if (!newProjectScreen->Validate()) - { - QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings")); - return; - } - - m_projectInfo = newProjectScreen->GetProjectInfo(); - m_projectTemplatePath = newProjectScreen->GetProjectTemplatePath(); - - // The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog. - m_gemCatalog->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/true); - } - } - - if (m_stack->currentIndex() != m_stack->count() - 1) - { - m_stack->setCurrentIndex(m_stack->currentIndex() + 1); - Update(); + // return to Project Settings page + PreviousScreen(); } else { - auto result = PythonBindingsInterface::Get()->CreateProject(m_projectTemplatePath, m_projectInfo); + // Configure Gems + NextScreen(); + } + } + + void CreateProjectCtrl::Update() + { + if (m_stack->currentWidget() == m_gemCatalogScreen) + { + m_header->setSubTitle(tr("Configure project with Gems")); + m_secondaryButton->setVisible(false); + } + else + { + m_header->setSubTitle(tr("Enter Project Details")); + m_secondaryButton->setVisible(true); + m_secondaryButton->setText(tr("Configure Gems")); + } + } + + void CreateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen) + { + if (screen == ProjectManagerScreen::GemCatalog) + { + HandleSecondaryButton(); + } + else + { + emit ChangeScreenRequest(screen); + } + } + + void CreateProjectCtrl::NextScreen() + { + if (m_stack->currentIndex() < m_stack->count()) + { + if(CurrentScreenIsValid()) + { + m_stack->setCurrentIndex(m_stack->currentIndex() + 1); + + QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); + m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true); + + Update(); + } + else + { + QMessageBox::warning(this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again.")); + } + } + } + + void CreateProjectCtrl::PreviousScreen() + { + // we don't require the current screen to be valid when moving back + if (m_stack->currentIndex() > 0) + { + m_stack->setCurrentIndex(m_stack->currentIndex() - 1); + Update(); + } + } +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED + + void CreateProjectCtrl::HandlePrimaryButton() + { + CreateProject(); + } + + bool CreateProjectCtrl::CurrentScreenIsValid() + { + if (m_stack->currentWidget() == m_newProjectSettingsScreen) + { + return m_newProjectSettingsScreen->Validate(); + } + + return true; + } + + void CreateProjectCtrl::CreateProject() + { + if (m_newProjectSettingsScreen->Validate()) + { + ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo(); + QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); + + auto result = PythonBindingsInterface::Get()->CreateProject(projectTemplatePath, projectInfo); if (result.IsSuccess()) { // automatically register the project - PythonBindingsInterface::Get()->AddProject(m_projectInfo.m_path); + PythonBindingsInterface::Get()->AddProject(projectInfo.m_path); + +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED - // adding gems is not implemented yet because we don't know what targets to add or how to add them emit ChangeScreenRequest(ProjectManagerScreen::Projects); } else { QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project.")); } - - // Enable/disable gems for the newly created project. - m_gemCatalog->EnableDisableGemsForProject(m_projectInfo.m_path); - } - } - - void CreateProjectCtrl::Update() - { - ScreenWidget* currentScreen = reinterpret_cast(m_stack->currentWidget()); - if (currentScreen && currentScreen->GetScreenEnum() == ProjectManagerScreen::GemCatalog) - { - m_header->setTitle(tr("Create Project")); - m_header->setSubTitle(tr("Configure project with Gems")); - m_nextButton->setText(tr("Create Project")); } else { - m_header->setTitle(tr("Create Project")); - m_header->setSubTitle(tr("Enter Project Details")); - m_nextButton->setText(tr("Next")); + QMessageBox::warning(this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again.")); } } diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h index 89d18a9ebc..e802b6845a 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h @@ -14,9 +14,11 @@ #if !defined(Q_MOC_RUN) #include #include -#include #endif +// due to current limitations, customizing template Gems is disabled +#define TEMPLATE_GEM_CONFIGURATION_ENABLED + QT_FORWARD_DECLARE_CLASS(QStackedWidget) QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QLabel) @@ -24,6 +26,8 @@ QT_FORWARD_DECLARE_CLASS(QLabel) namespace O3DE::ProjectManager { QT_FORWARD_DECLARE_CLASS(ScreenHeader) + QT_FORWARD_DECLARE_CLASS(NewProjectSettingsScreen) + QT_FORWARD_DECLARE_CLASS(GemCatalogScreen) class CreateProjectCtrl : public ScreenWidget @@ -36,21 +40,37 @@ namespace O3DE::ProjectManager protected slots: void HandleBackButton(); - void HandleNextButton(); + void HandlePrimaryButton(); + +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + void OnChangeScreenRequest(ProjectManagerScreen screen); + void HandleSecondaryButton(); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED private: +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED void Update(); + void NextScreen(); + void PreviousScreen(); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED - QStackedWidget* m_stack; - ScreenHeader* m_header; + bool CurrentScreenIsValid(); + void CreateProject(); - QPushButton* m_backButton; - QPushButton* m_nextButton; + QStackedWidget* m_stack = nullptr; + ScreenHeader* m_header = nullptr; + + QPushButton* m_primaryButton = nullptr; + +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + QPushButton* m_secondaryButton = nullptr; +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED QString m_projectTemplatePath; ProjectInfo m_projectInfo; - - GemCatalogScreen* m_gemCatalog = nullptr; + + NewProjectSettingsScreen* m_newProjectSettingsScreen = nullptr; + GemCatalogScreen* m_gemCatalogScreen = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp index c8dc8451ae..5faa6cb8bd 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp @@ -14,8 +14,12 @@ #include #include #include +#include #include #include +#include +#include +#include #include #include @@ -28,10 +32,12 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { - constexpr const char* k_pathProperty = "Path"; + constexpr const char* k_templateIndexProperty = "TemplateIndex"; NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent) : ProjectSettingsScreen(parent) @@ -59,30 +65,69 @@ namespace O3DE::ProjectManager projectTemplateDetailsLabel->setObjectName("projectTemplateDetailsLabel"); containerLayout->addWidget(projectTemplateDetailsLabel); - QHBoxLayout* templateLayout = new QHBoxLayout(this); - containerLayout->addItem(templateLayout); + + // we might have enough templates that we need to scroll + QScrollArea* templatesScrollArea = new QScrollArea(this); + QWidget* scrollWidget = new QWidget(); + + FlowLayout* flowLayout = new FlowLayout(0, s_spacerSize, s_spacerSize); + scrollWidget->setLayout(flowLayout); + + templatesScrollArea->setWidget(scrollWidget); + templatesScrollArea->setWidgetResizable(true); m_projectTemplateButtonGroup = new QButtonGroup(this); m_projectTemplateButtonGroup->setObjectName("templateButtonGroup"); + + // QButtonGroup has overloaded buttonClicked methods so we need the QOverload + connect( + m_projectTemplateButtonGroup, QOverload::of(&QButtonGroup::buttonClicked), this, + [=](QAbstractButton* button) + { + if (button && button->property(k_templateIndexProperty).isValid()) + { + int projectIndex = button->property(k_templateIndexProperty).toInt(); + UpdateTemplateDetails(m_templates.at(projectIndex)); + } + }); + auto templatesResult = PythonBindingsInterface::Get()->GetProjectTemplates(); if (templatesResult.IsSuccess() && !templatesResult.GetValue().isEmpty()) { - for (const ProjectTemplateInfo& projectTemplate : templatesResult.GetValue()) - { - QRadioButton* radioButton = new QRadioButton(projectTemplate.m_name, this); - radioButton->setProperty(k_pathProperty, projectTemplate.m_path); - m_projectTemplateButtonGroup->addButton(radioButton); + m_templates = templatesResult.GetValue(); - containerLayout->addWidget(radioButton); + // sort alphabetically by display name because they could be in any order + std::sort(m_templates.begin(), m_templates.end(), [](const ProjectTemplateInfo& arg1, const ProjectTemplateInfo& arg2) + { + return arg1.m_displayName.toLower() < arg2.m_displayName.toLower(); + }); + + for (int index = 0; index < m_templates.size(); ++index) + { + ProjectTemplateInfo projectTemplate = m_templates.at(index); + QString projectPreviewPath = projectTemplate.m_path + "/Template/preview.png"; + QFileInfo doesPreviewExist(projectPreviewPath); + if (!doesPreviewExist.exists() || !doesPreviewExist.isFile()) + { + projectPreviewPath = ":/DefaultTemplate.png"; + } + TemplateButton* templateButton = new TemplateButton(projectPreviewPath, projectTemplate.m_displayName, this); + templateButton->setCheckable(true); + templateButton->setProperty(k_templateIndexProperty, index); + + m_projectTemplateButtonGroup->addButton(templateButton); + + flowLayout->addWidget(templateButton); } m_projectTemplateButtonGroup->buttons().first()->setChecked(true); } + containerLayout->addWidget(templatesScrollArea); } projectTemplateWidget->setLayout(containerLayout); m_verticalLayout->addWidget(projectTemplateWidget); - QWidget* projectTemplateDetails = new QWidget(this); + QFrame* projectTemplateDetails = CreateTemplateDetails(s_templateDetailsContentMargin); projectTemplateDetails->setObjectName("projectTemplateDetails"); m_horizontalLayout->addWidget(projectTemplateDetails); } @@ -109,11 +154,71 @@ namespace O3DE::ProjectManager void NewProjectSettingsScreen::NotifyCurrentScreen() { + if (!m_templates.isEmpty()) + { + UpdateTemplateDetails(m_templates.first()); + } + Validate(); } QString NewProjectSettingsScreen::GetProjectTemplatePath() { - return m_projectTemplateButtonGroup->checkedButton()->property(k_pathProperty).toString(); + const int templateIndex = m_projectTemplateButtonGroup->checkedButton()->property(k_templateIndexProperty).toInt(); + return m_templates.at(templateIndex).m_path; + } + + QFrame* NewProjectSettingsScreen::CreateTemplateDetails(int margin) + { + QFrame* projectTemplateDetails = new QFrame(this); + projectTemplateDetails->setObjectName("projectTemplateDetails"); + QVBoxLayout* templateDetailsLayout = new QVBoxLayout(); + templateDetailsLayout->setContentsMargins(margin, margin, margin, margin); + templateDetailsLayout->setAlignment(Qt::AlignTop); + { + m_templateDisplayName = new QLabel(this); + m_templateDisplayName->setObjectName("displayName"); + templateDetailsLayout->addWidget(m_templateDisplayName); + + m_templateSummary = new QLabel(this); + m_templateSummary->setObjectName("summary"); + m_templateSummary->setWordWrap(true); + templateDetailsLayout->addWidget(m_templateSummary); + + QLabel* includedGemsTitle = new QLabel(tr("Included Gems"), this); + includedGemsTitle->setObjectName("includedGemsTitle"); + templateDetailsLayout->addWidget(includedGemsTitle); + + m_templateIncludedGems = new TagContainerWidget(this); + m_templateIncludedGems->setObjectName("includedGems"); + templateDetailsLayout->addWidget(m_templateIncludedGems); + +#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED + QLabel* moreGemsLabel = new QLabel(tr("Looking for more Gems?"), this); + moreGemsLabel->setObjectName("moreGems"); + templateDetailsLayout->addWidget(moreGemsLabel); + + QLabel* browseCatalogLabel = new QLabel(tr("Browse the Gems Catalog to further customize your project."), this); + browseCatalogLabel->setObjectName("browseCatalog"); + browseCatalogLabel->setWordWrap(true); + templateDetailsLayout->addWidget(browseCatalogLabel); + + QPushButton* configureGemsButton = new QPushButton(tr("Configure with more Gems"), this); + connect(configureGemsButton, &QPushButton::clicked, this, [=]() + { + emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog); + }); + templateDetailsLayout->addWidget(configureGemsButton); +#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED + } + projectTemplateDetails->setLayout(templateDetailsLayout); + return projectTemplateDetails; + } + + void NewProjectSettingsScreen::UpdateTemplateDetails(const ProjectTemplateInfo& templateInfo) + { + m_templateDisplayName->setText(templateInfo.m_displayName); + m_templateSummary->setText(templateInfo.m_summary); + m_templateIncludedGems->Update(templateInfo.m_includedGems); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h index 6a4b6ec57d..ce77915404 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h @@ -13,12 +13,17 @@ #if !defined(Q_MOC_RUN) #include +#include +#include #endif QT_FORWARD_DECLARE_CLASS(QButtonGroup) +QT_FORWARD_DECLARE_CLASS(QLabel) +QT_FORWARD_DECLARE_CLASS(QFrame) namespace O3DE::ProjectManager { + QT_FORWARD_DECLARE_CLASS(TagContainerWidget) class NewProjectSettingsScreen : public ProjectSettingsScreen { @@ -33,8 +38,17 @@ namespace O3DE::ProjectManager private: QString GetDefaultProjectPath(); + QFrame* CreateTemplateDetails(int margin); + void UpdateTemplateDetails(const ProjectTemplateInfo& templateInfo); QButtonGroup* m_projectTemplateButtonGroup; + QLabel* m_templateDisplayName; + QLabel* m_templateSummary; + TagContainerWidget* m_templateIncludedGems; + QVector m_templates; + + inline constexpr static int s_spacerSize = 20; + inline constexpr static int s_templateDetailsContentMargin = 20; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h index 0477968050..e75c64ec90 100644 --- a/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h @@ -31,6 +31,7 @@ namespace O3DE::ProjectManager QString m_name; QString m_path; QString m_summary; + QStringList m_includedGems; QStringList m_canonicalTags; QStringList m_userTags; }; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 37e636caef..3263505f9e 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -754,7 +754,7 @@ namespace O3DE::ProjectManager ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) { ProjectTemplateInfo templateInfo; - templateInfo.m_path = Py_To_String(path); + templateInfo.m_path = Py_To_String(pybind11::str(path)); auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) @@ -781,6 +781,13 @@ namespace O3DE::ProjectManager templateInfo.m_canonicalTags.push_back(Py_To_String(tag)); } } + if (data.contains("included_gems")) + { + for (auto gem : data["included_gems"]) + { + templateInfo.m_includedGems.push_back(Py_To_String(gem)); + } + } } catch ([[maybe_unused]] const std::exception& e) { diff --git a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp new file mode 100644 index 0000000000..41b5e51c99 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp @@ -0,0 +1,65 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + + TemplateButton::TemplateButton(const QString& imagePath, const QString& labelText, QWidget* parent) + : QPushButton(parent) + { + setAutoExclusive(true); + + setObjectName("templateButton"); + + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setSpacing(0); + vLayout->setContentsMargins(0, 0, 0, 0); + setLayout(vLayout); + + QLabel* image = new QLabel(this); + image->setObjectName("templateImage"); + image->setPixmap( + QPixmap(imagePath).scaled(QSize(s_templateImageWidth,s_templateImageHeight) , Qt::KeepAspectRatio, Qt::SmoothTransformation)); + vLayout->addWidget(image); + + QLabel* label = new QLabel(labelText, this); + label->setObjectName("templateLabel"); + vLayout->addWidget(label); + + connect(this, &QAbstractButton::toggled, this, &TemplateButton::onToggled); + } + + void TemplateButton::onToggled() + { + setProperty("Checked", isChecked()); + + // we must unpolish/polish every child after changing a property + // or else they won't use the correct stylesheet selector + for (auto child : findChildren()) + { + child->style()->unpolish(child); + child->style()->polish(child); + } + + style()->unpolish(this); + style()->polish(this); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h new file mode 100644 index 0000000000..db0f5f39c8 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h @@ -0,0 +1,37 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + class TemplateButton + : public QPushButton + { + Q_OBJECT // AUTOMOC + + public: + explicit TemplateButton(const QString& imagePath, const QString& labelText, QWidget* parent = nullptr); + ~TemplateButton() = default; + + protected slots: + void onToggled(); + + private: + inline constexpr static int s_templateImageWidth = 92; + inline constexpr static int s_templateImageHeight = 122; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index a7a36f26ab..40f450ab6f 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -60,6 +60,8 @@ set(FILES Source/LinkWidget.cpp Source/TagWidget.h Source/TagWidget.cpp + Source/TemplateButtonWidget.h + Source/TemplateButtonWidget.cpp Source/GemCatalog/GemCatalogHeaderWidget.h Source/GemCatalog/GemCatalogHeaderWidget.cpp Source/GemCatalog/GemCatalogScreen.h diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 26b868d315..6f74fb6b26 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -4,8 +4,9 @@ "restricted_platform_relative_path": "Templates", "origin": "The primary repo for DefaultProject goes here: i.e. http://www.mydomain.com", "license": "What license DefaultProject uses goes here: i.e. https://opensource.org/licenses/MIT", - "display_name": "DefaultProject", + "display_name": "Default", "summary": "A short description of DefaultProject.", + "included_gems": ["Atom","Camera","EMotionFX","UI","Maestro","Input","ImGui"], "canonical_tags": [], "user_tags": [ "DefaultProject" @@ -651,4 +652,4 @@ "origin": "Shaders" } ] -} \ No newline at end of file +} From 08db0584762545b87d09a48c897a8787852bcdbd Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 16:41:24 -0700 Subject: [PATCH 122/153] SPEC-2513 Fixes to enable w4436 and w4366 (#1157) * Fix for w4457 * Nothing to fix, seems we deleted all the code that was causing this offense * removing warning * another warning that doesnt trigger --- cmake/Platform/Common/MSVC/Configurations_msvc.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index 8c22677f91..bcff2adeb7 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -69,9 +69,7 @@ ly_append_configurations_options( /wd4267 # conversion, possible loss of data /wd4310 # cast truncates constant value /wd4324 # structure was padded due to alignment specifier - /wd4366 # the result of unary operator may be unaligned /wd4389 # comparison, signed/unsigned mismatch - /wd4436 # the result of unary operator may be unaligned # Enabling warnings that are disabled by default from /W4 # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019 From accd473ff5cd03a9e003dee4476c7c2581f4f125 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Fri, 4 Jun 2021 20:19:38 -0400 Subject: [PATCH 123/153] Adding python bindings for modifying project properties --- .../ProjectManager/Source/PythonBindings.cpp | 18 ++++++++++++++++++ .../ProjectManager/Source/PythonBindings.h | 6 ++++++ .../Source/PythonBindingsInterface.h | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 37e636caef..0acbf8ffaf 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -289,6 +289,7 @@ namespace O3DE::ProjectManager m_engineTemplate = pybind11::module::import("o3de.engine_template"); m_enableGemProject = pybind11::module::import("o3de.enable_gem"); m_disableGemProject = pybind11::module::import("o3de.disable_gem"); + m_editProjectProperties = pybind11::module::import("o3de.project_properties"); // make sure the engine is registered RegisterThisEngine(); @@ -686,6 +687,23 @@ namespace O3DE::ProjectManager return projectInfo; } + AZ::Outcome PythonBindings::ModifyProjectProperties(const QString& path, const QString& origin, const QString& displayName, + const QString& summary, const QString& icon, const QString& addTag, const QString& removeTag) + { + return ExecuteWithLockErrorHandling([&] + { + m_editProjectProperties.attr("edit_project_props")( + pybind11::str(path.toStdString()), //proj_path + pybind11::none(), //proj_name not used + origin.isNull() ? pybind11::none() : pybind11::str(origin.toStdString()), //new_origin + displayName.isNull() ? pybind11::none() : pybind11::str(displayName.toStdString()), //new_display + summary.isNull() ? pybind11::none() : pybind11::str(summary.toStdString()), //new_summary + icon.isNull() ? pybind11::none() : pybind11::str(icon.toStdString()), //new_icon + addTag.isNull() ? pybind11::none() : pybind11::str(addTag.toStdString()), //new_tag + removeTag.isNull() ? pybind11::none() : pybind11::str(removeTag.toStdString())); //remove_tag + }); + } + AZ::Outcome> PythonBindings::GetProjects() { QVector projects; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 278aa2d5d7..5f03d0ab28 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -53,6 +53,11 @@ namespace O3DE::ProjectManager bool UpdateProject(const ProjectInfo& projectInfo) override; AZ::Outcome AddGemToProject(const QString& gemPath, const QString& projectPath) override; AZ::Outcome RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override; + AZ::Outcome ModifyProjectProperties( + const QString& path, + const QString& origin = 0, + const QString& displayName = 0, + const QString& summary = 0, const QString& icon = 0, const QString& addTag = 0, const QString& removeTag = 0) override; // ProjectTemplate AZ::Outcome> GetProjectTemplates() override; @@ -78,5 +83,6 @@ namespace O3DE::ProjectManager pybind11::handle m_manifest; pybind11::handle m_enableGemProject; pybind11::handle m_disableGemProject; + pybind11::handle m_editProjectProperties; }; } diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 09d9187dbd..edc9510236 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -132,6 +132,25 @@ namespace O3DE::ProjectManager */ virtual AZ::Outcome AddGemToProject(const QString& gemPath, const QString& projectPath) = 0; + /** + * Change property in project json file + * @param path the absolute path to the gem + * @param origin the description or url for project origin (such as project host, repository, owner...etc) + * @param displayName the project display name + * @param summary short description of the project + * @param icon image used to represent the project + * @param addTag user tag to be added + * @param removeTag user tag to be removed + */ + virtual AZ::Outcome ModifyProjectProperties( + const QString& path, + const QString& origin = 0, + const QString& displayName = 0, + const QString& summary = 0, + const QString& icon = 0, + const QString& addTag = 0, + const QString& removeTag = 0) = 0; + /** * Remove gem to a project * @param gemPath the absolute path to the gem From d9b57bce678d11ef9a2f73cf45c3bd37422c8f0b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 4 Jun 2021 19:34:22 -0500 Subject: [PATCH 124/153] Fixed configuring of cmake when a project resides on a different drive than the engine (#1153) --- cmake/Platform/Common/Install_common.cmake | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 016c0d623d..4aeaf21e95 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -182,8 +182,20 @@ set_property(TARGET ${TARGET_NAME} endif() endif() - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" + if(IS_ABSOLUTE ${target_source_dir}) + # This normally applies the target_source_dir is outside of the engine root + # such as when invoking ly_setup_subdirectory from the project + # Therefore the final directory component of the target source directory is used first 8 characters + # of a SHA256 hash + string(SHA256 target_source_hash ${target_source_dir}) + string(SUBSTRING ${target_source_hash} 0 8 target_source_hash) + get_filename_component(target_source_folder_name ${target_source_dir} NAME) + set(target_source_dir "${target_source_folder_name}-${target_source_hash}") + endif() + + set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}) + file(GENERATE OUTPUT "${target_install_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${target_install_source_dir}/${NAME_PLACEHOLDER}_$.cmake" DESTINATION ${target_source_dir} COMPONENT ${install_component} ) @@ -235,18 +247,32 @@ function(ly_setup_subdirectory absolute_target_source_dir) endforeach() file(READ ${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment) - # Write out all the agreegated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeList.txt - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt + + if(IS_ABSOLUTE ${target_source_dir}) + # This normally applies the target_source_dir is outside of the engine root + # such as when invoking ly_setup_subdirectory from the project + # Therefore the final directory component of the target source directory is used first 8 characters + # of a SHA256 hash + string(SHA256 target_source_hash ${target_source_dir}) + string(SUBSTRING ${target_source_hash} 0 8 target_source_hash) + get_filename_component(target_source_folder_name ${target_source_dir} NAME) + set(target_source_dir "${target_source_folder_name}-${target_source_hash}") + endif() + + # Initialize the target install source directory to path underneath the current binary directory + set(target_install_source_dir ${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}) + # Write out all the aggregated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeLists.txt + file(WRITE ${target_install_source_dir}/CMakeLists.txt "${cmake_copyright_comment}" "${all_configured_targets}" "\n" "${CREATE_ALIASES_PLACEHOLDER}" ) - # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME + # get the component ID. if the property isn't set for the directory, it will auto fallback to use CMAKE_INSTALL_DEFAULT_COMPONENT_NAME get_property(install_component DIRECTORY ${absolute_target_source_dir} PROPERTY INSTALL_COMPONENT) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" + install(FILES "${target_install_source_dir}/CMakeLists.txt" DESTINATION ${target_source_dir} COMPONENT ${install_component} ) From 77f0d983c8475f24c874ccdd634a51c1ae8942ef Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 4 Jun 2021 19:34:28 -0500 Subject: [PATCH 125/153] Mac SystemFile_Apple.h build fix (#1159) --- .../AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h index 3967cafc90..2ebb79634a 100644 --- a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h +++ b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/IO/SystemFile_Apple.h @@ -14,6 +14,9 @@ #include #include #include +#include + +#include namespace AZ { From 74e5090f26f957adf75f141d70cc7d3da9c0bfdd Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 4 Jun 2021 18:08:52 -0700 Subject: [PATCH 126/153] Adding ExternalWarningLevel to the Directory.Build.props to get the default warning level for external headers to match the one we define through compile options (#1160) --- cmake/Platform/Common/Directory.Build.props | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/Platform/Common/Directory.Build.props b/cmake/Platform/Common/Directory.Build.props index b74fa48471..951d3c6605 100644 --- a/cmake/Platform/Common/Directory.Build.props +++ b/cmake/Platform/Common/Directory.Build.props @@ -15,4 +15,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. true true + + + TurnOffAllWarnings + + \ No newline at end of file From 3b60bcc0f1ab6707017d5698f55aa471e9ff598b Mon Sep 17 00:00:00 2001 From: AMZN-nggieber <52797929+AMZN-nggieber@users.noreply.github.com> Date: Fri, 4 Jun 2021 18:41:30 -0700 Subject: [PATCH 127/153] Project Manager Build Project from Projects Page (#1142) * Added loading bar mode to project button * Added ProjectBuilder files * commmit current progress for project building * Push current project building work * Full build commands built out and message boxes for lots of situation * Replaced defaultProjectImage placeholder * Added installed cmake path to builder process env PATH --- .../Resources/DefaultProjectImage.png | 4 +- .../Resources/ProjectManager.qss | 13 + .../Source/CreateProjectCtrl.cpp | 2 + .../ProjectManager/Source/ProjectBuilder.cpp | 250 ++++++++++++ .../ProjectManager/Source/ProjectBuilder.h | 73 ++++ .../Source/ProjectButtonWidget.cpp | 109 +++++- .../Source/ProjectButtonWidget.h | 19 +- .../ProjectManager/Source/ProjectInfo.cpp | 4 +- .../Tools/ProjectManager/Source/ProjectInfo.h | 4 +- .../ProjectManager/Source/ProjectUtils.cpp | 48 ++- .../ProjectManager/Source/ProjectUtils.h | 3 + .../ProjectManager/Source/ProjectsScreen.cpp | 363 ++++++++++++++---- .../ProjectManager/Source/ProjectsScreen.h | 35 +- .../ProjectManager/Source/PythonBindings.cpp | 2 +- .../ProjectManager/Source/ScreenWidget.h | 2 + .../ProjectManager/Source/ScreensCtrl.cpp | 1 + .../Tools/ProjectManager/Source/ScreensCtrl.h | 2 + .../Source/UpdateProjectCtrl.cpp | 14 +- .../project_manager_files.cmake | 2 + 19 files changed, 835 insertions(+), 115 deletions(-) create mode 100644 Code/Tools/ProjectManager/Source/ProjectBuilder.cpp create mode 100644 Code/Tools/ProjectManager/Source/ProjectBuilder.h diff --git a/Code/Tools/ProjectManager/Resources/DefaultProjectImage.png b/Code/Tools/ProjectManager/Resources/DefaultProjectImage.png index cc1eda5bb8..a3e13481c9 100644 --- a/Code/Tools/ProjectManager/Resources/DefaultProjectImage.png +++ b/Code/Tools/ProjectManager/Resources/DefaultProjectImage.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f82f22df64b93d4bec91e56b60efa3d5ce2915ce388a2dc627f1ab720678e3d5 -size 334987 +oid sha256:4a5881b8d6cfbc4ceefb14ab96844484fe19407ee030824768f9fcce2f729d35 +size 2949 diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 8b7470051c..c18d61fc24 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -362,6 +362,7 @@ QTabBar::tab:pressed #projectButton > #labelButton { border:1px solid white; } + #projectButton > #labelButton:hover, #projectButton > #labelButton:pressed { border:1px solid #1e70eb; @@ -401,6 +402,18 @@ QTabBar::tab:pressed max-height:278px; } +QProgressBar { + border: none; + background-color: transparent; + padding: 0px; + min-height: 14px; + font-size: 2px; +} + +QProgressBar::chunk { + background-color: #1E70EB; +} + /************** Gem Catalog **************/ #GemCatalogTitle { diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 4498a6bc82..c8ed3954ac 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -206,6 +206,8 @@ namespace O3DE::ProjectManager m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path); #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED + projectInfo.m_needsBuild = true; + emit NotifyBuildProject(projectInfo); emit ChangeScreenRequest(ProjectManagerScreen::Projects); } else diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp new file mode 100644 index 0000000000..8cdab93c6a --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp @@ -0,0 +1,250 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define MOCK_BUILD_PROJECT true + +namespace O3DE::ProjectManager +{ + // 10 Minutes + constexpr int MaxBuildTimeMSecs = 600000; + static const QString BuildPathPostfix = "windows_vs2019"; + static const QString ErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log"; + + ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo) + : QObject() + , m_projectInfo(projectInfo) + { + } + + void ProjectBuilderWorker::BuildProject() + { +#ifdef MOCK_BUILD_PROJECT + for (int i = 0; i < 10; ++i) + { + QThread::sleep(1); + UpdateProgress(i * 10); + } + Done(m_projectPath); +#else + EngineInfo engineInfo; + + AZ::Outcome engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); + if (engineInfoResult.IsSuccess()) + { + engineInfo = engineInfoResult.GetValue(); + } + else + { + emit Done(tr("Failed to get engine info.")); + return; + } + + // Show some kind of progress with very approximate estimates + UpdateProgress(1); + + QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment()); + // Append cmake path to PATH incase it is missing + QDir cmakePath(engineInfo.m_path); + cmakePath.cd("cmake/runtime/bin"); + QString pathValue = currentEnvironment.value("PATH"); + pathValue += ";" + cmakePath.path(); + currentEnvironment.insert("PATH", pathValue); + + QProcess configProjectProcess; + configProjectProcess.setProcessChannelMode(QProcess::MergedChannels); + configProjectProcess.setWorkingDirectory(m_projectInfo.m_path); + configProjectProcess.setProcessEnvironment(currentEnvironment); + + configProjectProcess.start( + "cmake", + QStringList + { + "-B", + QDir(m_projectInfo.m_path).filePath(BuildPathPostfix), + "-S", + m_projectInfo.m_path, + "-G", + "Visual Studio 16", + "-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath + }); + + if (!configProjectProcess.waitForStarted()) + { + emit Done(tr("Configuring project failed to start.")); + return; + } + if (!configProjectProcess.waitForFinished(MaxBuildTimeMSecs)) + { + WriteErrorLog(configProjectProcess.readAllStandardOutput()); + emit Done(tr("Configuring project timed out. See log for details")); + return; + } + + QString configProjectOutput(configProjectProcess.readAllStandardOutput()); + if (configProjectProcess.exitCode() != 0 || !configProjectOutput.contains("Generating done")) + { + WriteErrorLog(configProjectOutput); + emit Done(tr("Configuring project failed. See log for details.")); + return; + } + + UpdateProgress(20); + + QProcess buildProjectProcess; + buildProjectProcess.setProcessChannelMode(QProcess::MergedChannels); + buildProjectProcess.setWorkingDirectory(m_projectInfo.m_path); + buildProjectProcess.setProcessEnvironment(currentEnvironment); + + buildProjectProcess.start( + "cmake", + QStringList + { + "--build", + QDir(m_projectInfo.m_path).filePath(BuildPathPostfix), + "--target", + m_projectInfo.m_projectName + ".GameLauncher", + "Editor", + "--config", + "profile" + }); + + if (!buildProjectProcess.waitForStarted()) + { + emit Done(tr("Building project failed to start.")); + return; + } + if (!buildProjectProcess.waitForFinished(MaxBuildTimeMSecs)) + { + WriteErrorLog(configProjectProcess.readAllStandardOutput()); + emit Done(tr("Building project timed out. See log for details")); + return; + } + + QString buildProjectOutput(buildProjectProcess.readAllStandardOutput()); + if (configProjectProcess.exitCode() != 0) + { + WriteErrorLog(buildProjectOutput); + emit Done(tr("Building project failed. See log for details.")); + } + else + { + emit Done(""); + } +#endif + } + + QString ProjectBuilderWorker::LogFilePath() const + { + QDir logFilePath(m_projectInfo.m_path); + logFilePath.cd(BuildPathPostfix); + return logFilePath.filePath(ErrorLogPathPostfix); + } + + void ProjectBuilderWorker::WriteErrorLog(const QString& log) + { + QFile logFile(LogFilePath()); + // Overwrite file with truncate + if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + { + QTextStream output(&logFile); + output << log; + logFile.close(); + } + } + + ProjectBuilderController::ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent) + : QObject() + , m_projectInfo(projectInfo) + , m_projectButton(projectButton) + , m_parent(parent) + { + m_worker = new ProjectBuilderWorker(m_projectInfo); + m_worker->moveToThread(&m_workerThread); + + connect(&m_workerThread, &QThread::finished, m_worker, &ProjectBuilderWorker::deleteLater); + connect(&m_workerThread, &QThread::started, m_worker, &ProjectBuilderWorker::BuildProject); + connect(m_worker, &ProjectBuilderWorker::Done, this, &ProjectBuilderController::HandleResults); + connect(m_worker, &ProjectBuilderWorker::UpdateProgress, this, &ProjectBuilderController::UpdateUIProgress); + } + + ProjectBuilderController::~ProjectBuilderController() + { + m_workerThread.quit(); + m_workerThread.wait(); + } + + void ProjectBuilderController::Start() + { + m_workerThread.start(); + UpdateUIProgress(0); + } + + void ProjectBuilderController::SetProjectButton(ProjectButton* projectButton) + { + m_projectButton = projectButton; + } + + QString ProjectBuilderController::GetProjectPath() const + { + return m_projectInfo.m_path; + } + + void ProjectBuilderController::UpdateUIProgress(int progress) + { + if (m_projectButton) + { + m_projectButton->SetButtonOverlayText(QString("%1 (%2%)\n\n").arg(tr("Building Project..."), QString::number(progress))); + m_projectButton->SetProgressBarValue(progress); + } + } + + void ProjectBuilderController::HandleResults(const QString& result) + { + if (!result.isEmpty()) + { + if (result.contains(tr("log"))) + { + QMessageBox::StandardButton openLog = QMessageBox::critical( + m_parent, + tr("Project Failed to Build!"), + result + tr("\n\nWould you like to view log?"), + QMessageBox::No | QMessageBox::Yes); + + if (openLog == QMessageBox::Yes) + { + // Open application assigned to this file type + QDesktopServices::openUrl(QUrl("file:///" + m_worker->LogFilePath())); + } + } + else + { + QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result); + } + } + + emit Done(); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilder.h b/Code/Tools/ProjectManager/Source/ProjectBuilder.h new file mode 100644 index 0000000000..de84a351ee --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectBuilder.h @@ -0,0 +1,73 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +#include +#endif + +namespace O3DE::ProjectManager +{ + QT_FORWARD_DECLARE_CLASS(ProjectButton) + + class ProjectBuilderWorker : public QObject + { + Q_OBJECT + + public: + explicit ProjectBuilderWorker(const ProjectInfo& projectInfo); + ~ProjectBuilderWorker() = default; + + QString LogFilePath() const; + + public slots: + void BuildProject(); + + signals: + void UpdateProgress(int progress); + void Done(QString result); + + private: + void WriteErrorLog(const QString& log); + + ProjectInfo m_projectInfo; + }; + + class ProjectBuilderController : public QObject + { + Q_OBJECT + + public: + explicit ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent = nullptr); + ~ProjectBuilderController(); + + void SetProjectButton(ProjectButton* projectButton); + QString GetProjectPath() const; + + public slots: + void Start(); + void UpdateUIProgress(int progress); + void HandleResults(const QString& result); + + signals: + void Done(); + + private: + ProjectInfo m_projectInfo; + ProjectBuilderWorker* m_worker; + QThread m_workerThread; + ProjectButton* m_projectButton; + QWidget* m_parent; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index ee4d48fe7f..db1b1a4850 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -31,11 +32,26 @@ namespace O3DE::ProjectManager : QLabel(parent) { setObjectName("labelButton"); + + QVBoxLayout* vLayout = new QVBoxLayout(this); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->setSpacing(5); + + setLayout(vLayout); m_overlayLabel = new QLabel("", this); m_overlayLabel->setObjectName("labelButtonOverlay"); m_overlayLabel->setWordWrap(true); m_overlayLabel->setAlignment(Qt::AlignCenter); m_overlayLabel->setVisible(false); + vLayout->addWidget(m_overlayLabel); + + m_buildButton = new QPushButton(tr("Build Project"), this); + m_buildButton->setVisible(false); + + m_progressBar = new QProgressBar(this); + m_progressBar->setObjectName("labelButtonProgressBar"); + m_progressBar->setVisible(false); + vLayout->addWidget(m_progressBar); } void LabelButton::mousePressEvent([[maybe_unused]] QMouseEvent* event) @@ -57,7 +73,22 @@ namespace O3DE::ProjectManager m_overlayLabel->setText(text); } - ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent) + QLabel* LabelButton::GetOverlayLabel() + { + return m_overlayLabel; + } + + QProgressBar* LabelButton::GetProgressBar() + { + return m_progressBar; + } + + QPushButton* LabelButton::GetBuildButton() + { + return m_buildButton; + } + + ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent, bool processing) : QFrame(parent) , m_projectInfo(projectInfo) { @@ -66,10 +97,18 @@ namespace O3DE::ProjectManager m_projectInfo.m_imagePath = ":/DefaultProjectImage.png"; } - Setup(); + BaseSetup(); + if (processing) + { + ProcessingSetup(); + } + else + { + ReadySetup(); + } } - void ProjectButton::Setup() + void ProjectButton::BaseSetup() { setObjectName("projectButton"); @@ -87,8 +126,37 @@ namespace O3DE::ProjectManager m_projectImageLabel->setPixmap( QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); + m_projectFooter = new QFrame(this); + QHBoxLayout* hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(0, 0, 0, 0); + m_projectFooter->setLayout(hLayout); + { + QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this); + hLayout->addWidget(projectNameLabel); + } + + vLayout->addWidget(m_projectFooter); + } + + void ProjectButton::ProcessingSetup() + { + m_projectImageLabel->GetOverlayLabel()->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); + m_projectImageLabel->SetEnabled(false); + m_projectImageLabel->SetOverlayText(tr("Processing...\n\n")); + + QProgressBar* progressBar = m_projectImageLabel->GetProgressBar(); + progressBar->setVisible(true); + progressBar->setValue(0); + } + + void ProjectButton::ReadySetup() + { + connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); + connect(m_projectImageLabel->GetBuildButton(), &QPushButton::clicked, [this](){ emit BuildProject(m_projectInfo); }); + QMenu* menu = new QMenu(this); menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); }); + menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); }); menu->addSeparator(); menu->addAction(tr("Open Project folder..."), this, [this]() { @@ -100,30 +168,33 @@ namespace O3DE::ProjectManager menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); }); menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); }); - QFrame* footer = new QFrame(this); - QHBoxLayout* hLayout = new QHBoxLayout(); - hLayout->setContentsMargins(0, 0, 0, 0); - footer->setLayout(hLayout); - { - QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this); - hLayout->addWidget(projectNameLabel); - - QPushButton* projectMenuButton = new QPushButton(this); - projectMenuButton->setObjectName("projectMenuButton"); - projectMenuButton->setMenu(menu); - hLayout->addWidget(projectMenuButton); - } - - vLayout->addWidget(footer); + QPushButton* projectMenuButton = new QPushButton(this); + projectMenuButton->setObjectName("projectMenuButton"); + projectMenuButton->setMenu(menu); + m_projectFooter->layout()->addWidget(projectMenuButton); } - void ProjectButton::SetButtonEnabled(bool enabled) + void ProjectButton::SetLaunchButtonEnabled(bool enabled) { m_projectImageLabel->SetEnabled(enabled); } + void ProjectButton::ShowBuildButton(bool show) + { + QSpacerItem* buttonSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding); + + m_projectImageLabel->layout()->addItem(buttonSpacer); + m_projectImageLabel->layout()->addWidget(m_projectImageLabel->GetBuildButton()); + m_projectImageLabel->GetBuildButton()->setVisible(show); + } + void ProjectButton::SetButtonOverlayText(const QString& text) { m_projectImageLabel->SetOverlayText(text); } + + void ProjectButton::SetProgressBarValue(int progress) + { + m_projectImageLabel->GetProgressBar()->setValue(progress); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h index bb61f7354b..1178c8ea76 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h @@ -21,6 +21,7 @@ QT_FORWARD_DECLARE_CLASS(QPixmap) QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QAction) +QT_FORWARD_DECLARE_CLASS(QProgressBar) namespace O3DE::ProjectManager { @@ -36,6 +37,10 @@ namespace O3DE::ProjectManager void SetEnabled(bool enabled); void SetOverlayText(const QString& text); + QLabel* GetOverlayLabel(); + QProgressBar* GetProgressBar(); + QPushButton* GetBuildButton(); + signals: void triggered(); @@ -44,6 +49,8 @@ namespace O3DE::ProjectManager private: QLabel* m_overlayLabel; + QProgressBar* m_progressBar; + QPushButton* m_buildButton; bool m_enabled = true; }; @@ -53,11 +60,13 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr); + explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr, bool processing = false); ~ProjectButton() = default; - void SetButtonEnabled(bool enabled); + void SetLaunchButtonEnabled(bool enabled); + void ShowBuildButton(bool show); void SetButtonOverlayText(const QString& text); + void SetProgressBarValue(int progress); signals: void OpenProject(const QString& projectName); @@ -65,11 +74,15 @@ namespace O3DE::ProjectManager void CopyProject(const QString& projectName); void RemoveProject(const QString& projectName); void DeleteProject(const QString& projectName); + void BuildProject(const ProjectInfo& projectInfo); private: - void Setup(); + void BaseSetup(); + void ProcessingSetup(); + void ReadySetup(); ProjectInfo m_projectInfo; LabelButton* m_projectImageLabel; + QFrame* m_projectFooter; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index f0dc05cc62..da0b4ebd61 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -15,13 +15,13 @@ namespace O3DE::ProjectManager { ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, - const QString& imagePath, const QString& backgroundImagePath, bool isNew) + const QString& imagePath, const QString& backgroundImagePath, bool needsBuild) : m_path(path) , m_projectName(projectName) , m_displayName(displayName) , m_imagePath(imagePath) , m_backgroundImagePath(backgroundImagePath) - , m_isNew(isNew) + , m_needsBuild(needsBuild) { } diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 71fa12b344..857e6ea4d5 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -24,7 +24,7 @@ namespace O3DE::ProjectManager public: ProjectInfo() = default; ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, - const QString& imagePath, const QString& backgroundImagePath, bool isNew); + const QString& imagePath, const QString& backgroundImagePath, bool needsBuild); bool operator==(const ProjectInfo& rhs); bool operator!=(const ProjectInfo& rhs); @@ -42,6 +42,6 @@ namespace O3DE::ProjectManager QString m_backgroundImagePath; // Used in project creation - bool m_isNew = false; //! Is this a new project or existing + bool m_needsBuild = false; //! Does this project need to be built }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index 58e4c5c60f..3e2b3c13e1 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -16,7 +16,9 @@ #include #include #include -#include +#include +#include +#include namespace O3DE::ProjectManager { @@ -192,6 +194,49 @@ namespace O3DE::ProjectManager return true; } + static bool IsVS2019Installed_internal() + { + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + QString programFilesPath = environment.value("ProgramFiles(x86)"); + QString vsWherePath = programFilesPath + "\\Microsoft Visual Studio\\Installer\\vswhere.exe"; + + QFileInfo vsWhereFile(vsWherePath); + if (vsWhereFile.exists() && vsWhereFile.isFile()) + { + QProcess vsWhereProcess; + vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels); + + vsWhereProcess.start( + vsWherePath, + QStringList{ "-version", "16.0", "-latest", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "isComplete" }); + + if (!vsWhereProcess.waitForStarted()) + { + return false; + } + + while (vsWhereProcess.waitForReadyRead()) + { + } + + QString vsWhereOutput(vsWhereProcess.readAllStandardOutput()); + if (vsWhereOutput.startsWith("1")) + { + return true; + } + } + + return false; + } + + bool IsVS2019Installed() + { + static bool vs2019Installed = IsVS2019Installed_internal(); + + return vs2019Installed; + } + ProjectManagerScreen GetProjectManagerScreen(const QString& screen) { auto iter = s_ProjectManagerStringNames.find(screen); @@ -202,6 +247,5 @@ namespace O3DE::ProjectManager return ProjectManagerScreen::Invalid; } - } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index d556d682f2..9c711ad187 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -25,6 +25,9 @@ namespace O3DE::ProjectManager bool CopyProject(const QString& origPath, const QString& newPath); bool DeleteProjectFiles(const QString& path, bool force = false); bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent = nullptr); + + bool IsVS2019Installed(); + ProjectManagerScreen GetProjectManagerScreen(const QString& screen); } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 425aa8514d..8e41e52643 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -42,6 +44,8 @@ #include #include #include +#include +#include //#define DISPLAY_PROJECT_DEV_DATA true @@ -66,6 +70,14 @@ namespace O3DE::ProjectManager m_stack->addWidget(m_projectsContent); vLayout->addWidget(m_stack); + + connect(reinterpret_cast(parent), &ScreensCtrl::NotifyBuildProject, this, &ProjectsScreen::SuggestBuildProject); + } + + ProjectsScreen::~ProjectsScreen() + + { + delete m_currentBuilder; } QFrame* ProjectsScreen::CreateFirstTimeContent() @@ -110,7 +122,7 @@ namespace O3DE::ProjectManager return frame; } - QFrame* ProjectsScreen::CreateProjectsContent() + QFrame* ProjectsScreen::CreateProjectsContent(QString buildProjectPath, ProjectButton** projectButton) { QFrame* frame = new QFrame(this); frame->setObjectName("projectsContent"); @@ -158,30 +170,43 @@ namespace O3DE::ProjectManager projectsScrollArea->setWidgetResizable(true); #ifndef DISPLAY_PROJECT_DEV_DATA + // Iterate once to insert building project first + if (!buildProjectPath.isEmpty()) + { + buildProjectPath = QDir::fromNativeSeparators(buildProjectPath); + for (auto project : projectsResult.GetValue()) + { + if (QDir::fromNativeSeparators(project.m_path) == buildProjectPath) + { + ProjectButton* buildingProjectButton = CreateProjectButton(project, flowLayout, true); + + if (projectButton) + { + *projectButton = buildingProjectButton; + } + + break; + } + } + } + for (auto project : projectsResult.GetValue()) #else ProjectInfo project = projectsResult.GetValue().at(0); for (int i = 0; i < 15; i++) #endif { - ProjectButton* projectButton; - - QString projectPreviewPath = project.m_path + m_projectPreviewImagePath; - QFileInfo doesPreviewExist(projectPreviewPath); - if (doesPreviewExist.exists() && doesPreviewExist.isFile()) + // Add all other projects skipping building project + // Safe if no building project because it is just an empty string + if (project.m_path != buildProjectPath) { - project.m_imagePath = projectPreviewPath; + ProjectButton* projectButtonWidget = CreateProjectButton(project, flowLayout); + + if (RequiresBuildProjectIterator(project.m_path) != m_requiresBuild.end()) + { + projectButtonWidget->ShowBuildButton(true); + } } - - projectButton = new ProjectButton(project, this); - - flowLayout->addWidget(projectButton); - - connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject); - connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject); - connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject); - connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); - connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); } layout->addWidget(projectsScrollArea); @@ -191,6 +216,60 @@ namespace O3DE::ProjectManager return frame; } + ProjectButton* ProjectsScreen::CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing) + { + ProjectButton* projectButton; + + QString projectPreviewPath = project.m_path + m_projectPreviewImagePath; + QFileInfo doesPreviewExist(projectPreviewPath); + if (doesPreviewExist.exists() && doesPreviewExist.isFile()) + { + project.m_imagePath = projectPreviewPath; + } + + projectButton = new ProjectButton(project, this, processing); + + flowLayout->addWidget(projectButton); + + if (!processing) + { + connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject); + connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject); + connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject); + connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); + connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); + } + connect(projectButton, &ProjectButton::BuildProject, this, &ProjectsScreen::QueueBuildProject); + + return projectButton; + } + + void ProjectsScreen::ResetProjectsContent() + { + // refresh the projects content by re-creating it for now + if (m_projectsContent) + { + m_stack->removeWidget(m_projectsContent); + m_projectsContent->deleteLater(); + } + + // Make sure to update builder with latest Project Button + if (m_currentBuilder) + { + ProjectButton* projectButtonPtr; + + m_projectsContent = CreateProjectsContent(m_currentBuilder->GetProjectPath(), &projectButtonPtr); + m_currentBuilder->SetProjectButton(projectButtonPtr); + } + else + { + m_projectsContent = CreateProjectsContent(); + } + + m_stack->addWidget(m_projectsContent); + m_stack->setCurrentWidget(m_projectsContent); + } + ProjectManagerScreen ProjectsScreen::GetScreenEnum() { return ProjectManagerScreen::Projects; @@ -237,7 +316,7 @@ namespace O3DE::ProjectManager { if (ProjectUtils::AddProjectDialog(this)) { - emit ResetScreenRequest(ProjectManagerScreen::Projects); + ResetProjectsContent(); emit ChangeScreenRequest(ProjectManagerScreen::Projects); } } @@ -245,38 +324,47 @@ namespace O3DE::ProjectManager { if (!projectPath.isEmpty()) { - AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); - AZStd::string executableFilename = "Editor"; - AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); - auto cmdPath = AZ::IO::FixedMaxPathString::format("%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str()); + if (!WarnIfInBuildQueue(projectPath)) + { + AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); + AZStd::string executableFilename = "Editor"; + AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); + auto cmdPath = AZ::IO::FixedMaxPathString::format( + "%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), + projectPath.toStdString().c_str()); - AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; - processLaunchInfo.m_commandlineParameters = cmdPath; - bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo); - if (!launchSucceeded) - { - AZ_Error("ProjectManager", false, "Failed to launch editor"); - QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid.")); - } - else - { - // prevent the user from accidentally pressing the button while the editor is launching - // and let them know what's happening - ProjectButton* button = qobject_cast(sender()); - if (button) + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + processLaunchInfo.m_commandlineParameters = cmdPath; + bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo); + if (!launchSucceeded) { - button->SetButtonEnabled(false); - button->SetButtonOverlayText(tr("Opening Editor...")); + AZ_Error("ProjectManager", false, "Failed to launch editor"); + QMessageBox::critical( + this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid.")); } + else + { + // prevent the user from accidentally pressing the button while the editor is launching + // and let them know what's happening + ProjectButton* button = qobject_cast(sender()); + if (button) + { + button->SetLaunchButtonEnabled(false); + button->SetButtonOverlayText(tr("Opening Editor...")); + } - // enable the button after 3 seconds - constexpr int waitTimeInMs = 3000; - QTimer::singleShot(waitTimeInMs, this, [this, button] { - if (button) + // enable the button after 3 seconds + constexpr int waitTimeInMs = 3000; + QTimer::singleShot( + waitTimeInMs, this, + [this, button] { - button->SetButtonEnabled(true); - } - }); + if (button) + { + button->SetLaunchButtonEnabled(true); + } + }); + } } } else @@ -288,38 +376,90 @@ namespace O3DE::ProjectManager } void ProjectsScreen::HandleEditProject(const QString& projectPath) { - emit NotifyCurrentProject(projectPath); - emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject); + if (!WarnIfInBuildQueue(projectPath)) + { + emit NotifyCurrentProject(projectPath); + emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject); + } } void ProjectsScreen::HandleCopyProject(const QString& projectPath) { - // Open file dialog and choose location for copied project then register copy with O3DE - if (ProjectUtils::CopyProjectDialog(projectPath, this)) + if (!WarnIfInBuildQueue(projectPath)) { - emit ResetScreenRequest(ProjectManagerScreen::Projects); - emit ChangeScreenRequest(ProjectManagerScreen::Projects); + // Open file dialog and choose location for copied project then register copy with O3DE + if (ProjectUtils::CopyProjectDialog(projectPath, this)) + { + ResetProjectsContent(); + emit ChangeScreenRequest(ProjectManagerScreen::Projects); + } } } void ProjectsScreen::HandleRemoveProject(const QString& projectPath) { - // Unregister Project from O3DE and reload projects - if (ProjectUtils::UnregisterProject(projectPath)) + if (!WarnIfInBuildQueue(projectPath)) { - emit ResetScreenRequest(ProjectManagerScreen::Projects); - emit ChangeScreenRequest(ProjectManagerScreen::Projects); + // Unregister Project from O3DE and reload projects + if (ProjectUtils::UnregisterProject(projectPath)) + { + ResetProjectsContent(); + emit ChangeScreenRequest(ProjectManagerScreen::Projects); + } } } void ProjectsScreen::HandleDeleteProject(const QString& projectPath) { - QMessageBox::StandardButton warningResult = QMessageBox::warning( - this, tr("Delete Project"), tr("Are you sure?\nProject will be removed from O3DE and directory will be deleted!"), - QMessageBox::No | QMessageBox::Yes); - - if (warningResult == QMessageBox::Yes) + if (!WarnIfInBuildQueue(projectPath)) { - // Remove project from O3DE and delete from disk - HandleRemoveProject(projectPath); - ProjectUtils::DeleteProjectFiles(projectPath); + QMessageBox::StandardButton warningResult = QMessageBox::warning(this, + tr("Delete Project"), + tr("Are you sure?\nProject will be unregistered from O3DE and project directory will be deleted from your disk."), + QMessageBox::No | QMessageBox::Yes); + + if (warningResult == QMessageBox::Yes) + { + // Remove project from O3DE and delete from disk + HandleRemoveProject(projectPath); + ProjectUtils::DeleteProjectFiles(projectPath); + } + } + } + + void ProjectsScreen::SuggestBuildProject(const ProjectInfo& projectInfo) + { + if (projectInfo.m_needsBuild) + { + if (RequiresBuildProjectIterator(projectInfo.m_path) == m_requiresBuild.end()) + { + m_requiresBuild.append(projectInfo); + } + ResetProjectsContent(); + } + else + { + QMessageBox::information(this, + tr("Project Should be rebuilt."), + projectInfo.m_projectName + tr(" project likely needs to be rebuilt.")); + } + } + + void ProjectsScreen::QueueBuildProject(const ProjectInfo& projectInfo) + { + auto requiredIter = RequiresBuildProjectIterator(projectInfo.m_path); + if (requiredIter != m_requiresBuild.end()) + { + m_requiresBuild.erase(requiredIter); + } + + if (!BuildQueueContainsProject(projectInfo.m_path)) + { + if (m_buildQueue.empty() && !m_currentBuilder) + { + StartProjectBuild(projectInfo); + } + else + { + m_buildQueue.append(projectInfo); + } } } @@ -331,17 +471,7 @@ namespace O3DE::ProjectManager } else { - // refresh the projects content by re-creating it for now - if (m_projectsContent) - { - m_stack->removeWidget(m_projectsContent); - m_projectsContent->deleteLater(); - } - - m_projectsContent = CreateProjectsContent(); - - m_stack->addWidget(m_projectsContent); - m_stack->setCurrentWidget(m_projectsContent); + ResetProjectsContent(); } } @@ -363,4 +493,89 @@ namespace O3DE::ProjectManager return displayFirstTimeContent; } + void ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo) + { + if (ProjectUtils::IsVS2019Installed()) + { + QMessageBox::StandardButton buildProject = QMessageBox::information( + this, + tr("Building \"%1\"").arg(projectInfo.m_projectName), + tr("Ready to build \"%1\"?").arg(projectInfo.m_projectName), + QMessageBox::No | QMessageBox::Yes); + + if (buildProject == QMessageBox::Yes) + { + m_currentBuilder = new ProjectBuilderController(projectInfo, nullptr, this); + ResetProjectsContent(); + connect(m_currentBuilder, &ProjectBuilderController::Done, this, &ProjectsScreen::ProjectBuildDone); + + m_currentBuilder->Start(); + } + else + { + ProjectBuildDone(); + } + } + } + + void ProjectsScreen::ProjectBuildDone() + { + delete m_currentBuilder; + m_currentBuilder = nullptr; + + if (!m_buildQueue.empty()) + { + StartProjectBuild(m_buildQueue.front()); + m_buildQueue.pop_front(); + } + else + { + ResetProjectsContent(); + } + } + + QList::iterator ProjectsScreen::RequiresBuildProjectIterator(const QString& projectPath) + { + QString nativeProjPath(QDir::toNativeSeparators(projectPath)); + auto projectIter = m_requiresBuild.begin(); + for (; projectIter != m_requiresBuild.end(); ++projectIter) + { + if (QDir::toNativeSeparators(projectIter->m_path) == nativeProjPath) + { + break; + } + } + + return projectIter; + } + + bool ProjectsScreen::BuildQueueContainsProject(const QString& projectPath) + { + QString nativeProjPath(QDir::toNativeSeparators(projectPath)); + for (const ProjectInfo& project : m_buildQueue) + { + if (QDir::toNativeSeparators(project.m_path) == nativeProjPath) + { + return true; + } + } + + return false; + } + + bool ProjectsScreen::WarnIfInBuildQueue(const QString& projectPath) + { + if (BuildQueueContainsProject(projectPath)) + { + QMessageBox::warning( + this, + tr("Action Temporarily Disabled!"), + tr("Action not allowed on projects in build queue.")); + + return true; + } + + return false; + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h index e02b34525b..bc28d4ef30 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.h +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h @@ -13,21 +13,28 @@ #if !defined(Q_MOC_RUN) #include +#include + +#include #endif QT_FORWARD_DECLARE_CLASS(QPaintEvent) QT_FORWARD_DECLARE_CLASS(QFrame) QT_FORWARD_DECLARE_CLASS(QStackedWidget) +QT_FORWARD_DECLARE_CLASS(QLayout) namespace O3DE::ProjectManager { + QT_FORWARD_DECLARE_CLASS(ProjectBuilderController); + QT_FORWARD_DECLARE_CLASS(ProjectButton); + class ProjectsScreen : public ScreenWidget { public: explicit ProjectsScreen(QWidget* parent = nullptr); - ~ProjectsScreen() = default; + ~ProjectsScreen(); ProjectManagerScreen GetScreenEnum() override; QString GetTabText() override; @@ -35,6 +42,7 @@ namespace O3DE::ProjectManager protected: void NotifyCurrentScreen() override; + void ProjectBuildDone(); protected slots: void HandleNewProjectButton(); @@ -45,19 +53,32 @@ namespace O3DE::ProjectManager void HandleRemoveProject(const QString& projectPath); void HandleDeleteProject(const QString& projectPath); + void SuggestBuildProject(const ProjectInfo& projectInfo); + void QueueBuildProject(const ProjectInfo& projectInfo); + void paintEvent(QPaintEvent* event) override; private: QFrame* CreateFirstTimeContent(); - QFrame* CreateProjectsContent(); + QFrame* CreateProjectsContent(QString buildProjectPath = "", ProjectButton** projectButton = nullptr); + ProjectButton* CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing = false); + void ResetProjectsContent(); bool ShouldDisplayFirstTimeContent(); - QAction* m_createNewProjectAction; - QAction* m_addExistingProjectAction; + void StartProjectBuild(const ProjectInfo& projectInfo); + QList::iterator RequiresBuildProjectIterator(const QString& projectPath); + bool BuildQueueContainsProject(const QString& projectPath); + bool WarnIfInBuildQueue(const QString& projectPath); + + QAction* m_createNewProjectAction = nullptr; + QAction* m_addExistingProjectAction = nullptr; QPixmap m_background; - QFrame* m_firstTimeContent; - QFrame* m_projectsContent; - QStackedWidget* m_stack; + QFrame* m_firstTimeContent = nullptr; + QFrame* m_projectsContent = nullptr; + QStackedWidget* m_stack = nullptr; + QList m_requiresBuild; + QQueue m_buildQueue; + ProjectBuilderController* m_currentBuilder = nullptr; const QString m_projectPreviewImagePath = "/preview.png"; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 3263505f9e..5f4bb833d8 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -667,7 +667,7 @@ namespace O3DE::ProjectManager { ProjectInfo projectInfo; projectInfo.m_path = Py_To_String(path); - projectInfo.m_isNew = false; + projectInfo.m_needsBuild = false; auto projectData = m_manifest.attr("get_project_json_data")(pybind11::none(), path); if (pybind11::isinstance(projectData)) diff --git a/Code/Tools/ProjectManager/Source/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h index 2ad6d30201..47baed261c 100644 --- a/Code/Tools/ProjectManager/Source/ScreenWidget.h +++ b/Code/Tools/ProjectManager/Source/ScreenWidget.h @@ -13,6 +13,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include @@ -61,6 +62,7 @@ namespace O3DE::ProjectManager void GotoPreviousScreenRequest(); void ResetScreenRequest(ProjectManagerScreen screen); void NotifyCurrentProject(const QString& projectPath); + void NotifyBuildProject(const ProjectInfo& projectInfo); }; diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp index 52fcbf354a..646f66a557 100644 --- a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp @@ -177,6 +177,7 @@ namespace O3DE::ProjectManager connect(newScreen, &ScreenWidget::GotoPreviousScreenRequest, this, &ScreensCtrl::GotoPreviousScreen); connect(newScreen, &ScreenWidget::ResetScreenRequest, this, &ScreensCtrl::ResetScreen); connect(newScreen, &ScreenWidget::NotifyCurrentProject, this, &ScreensCtrl::NotifyCurrentProject); + connect(newScreen, &ScreenWidget::NotifyBuildProject, this, &ScreensCtrl::NotifyBuildProject); } void ScreensCtrl::ResetAllScreens() diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.h b/Code/Tools/ProjectManager/Source/ScreensCtrl.h index 3b51ed529a..841108dff7 100644 --- a/Code/Tools/ProjectManager/Source/ScreensCtrl.h +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.h @@ -13,6 +13,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include @@ -39,6 +40,7 @@ namespace O3DE::ProjectManager signals: void NotifyCurrentProject(const QString& projectPath); + void NotifyBuildProject(const ProjectInfo& projectInfo); public slots: bool ChangeToScreen(ProjectManagerScreen screen); diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index a383a0f93b..6fcb1b1c71 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -119,7 +119,9 @@ namespace O3DE::ProjectManager void UpdateProjectCtrl::HandleNextButton() { - if (m_stack->currentIndex() == ScreenOrder::Settings) + bool shouldRebuild = false; + + if (m_stack->currentIndex() == ScreenOrder::Settings && m_updateSettingsScreen) { if (m_updateSettingsScreen) { @@ -155,11 +157,17 @@ namespace O3DE::ProjectManager m_projectInfo = newProjectSettings; } } - - if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen) + else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen) { // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project. m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); + + shouldRebuild = true; + } + + if (shouldRebuild) + { + emit NotifyBuildProject(m_projectInfo); } emit ChangeScreenRequest(ProjectManagerScreen::Projects); diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 40f450ab6f..eb9cd1145e 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -38,6 +38,8 @@ set(FILES Source/ProjectInfo.cpp Source/ProjectUtils.h Source/ProjectUtils.cpp + Source/ProjectBuilder.h + Source/ProjectBuilder.cpp Source/UpdateProjectSettingsScreen.h Source/UpdateProjectSettingsScreen.cpp Source/NewProjectSettingsScreen.h From 9df995dd264516dfd821ca5c51c84400f14f957c Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Fri, 4 Jun 2021 20:57:44 -0500 Subject: [PATCH 128/153] Temporal anti-aliasing and constrast adaptive sharpening (#1161) First version of temporal antialiasing and contrast adaptive sharpening for GA. Works well in most cases but still has a few issues that will need additional time. This is only the passes and shaders with no exposure to the editor. TAA and CAS can be turned on by enabling their respective passes in the pipeline. All of the code has been previously reviewed in smaller PRs into the taa_staging branch: aws-lumberyard-dev#29 aws-lumberyard-dev#53 aws-lumberyard-dev#73 aws-lumberyard-dev#79 aws-lumberyard-dev#84 Main issues: - Bloom doesn't play nice with TAA and seems to greatly amplify any flickering - AuxGeom jitters with the camera, so TAA doesn't currently work well in editor - Transparencies don't have correct motion vectors. History rectification keeps this from looking too bad, but could still be improved - There is still more that could be done to inhibit flickering, usually from specular aliasing - Motion vectors aren't correct on POM unless PDO is turned on, which can result in some blurring during motion. - SSAO can contribute to flickering in its default half res configuration. Changing this to full res mitigates the problem. Squashed merge of the following: * [ATOM-13987] Initial checkin of Taa pass. * TAA pass setup WIP. (does not work yet due to pass configuration issues). * Taa WIP - Camera motion vectors fixed and hooked up. TAA does simple reprojection and rejection based on depth. * Small update to use lerp and add some comments. * Fix issue with attachments not being set up on bindings at initialization. Fixing issue with half-pixel offsets in TAA shader * - Motion vector passes now use the same output with mesh motion vectors overwriting camera motion vectors. - Taa pass now works with multiple pipelines. - Cleaned up TAA shader a bit. * Fixes from PR review. * Adding check for multiple attachments of the same name with different resources in Pass::ImportAttachments(). * Adding camera jitter with configurable position count. Updated TAA to blend in tonemapped space. * Fixes from PR review. Fixing camera motion vectors for background (infinite distance) * Updates to taa shader from PR review * Adding a rcp input color size. * Fix comment on PassAttachment::Update() * Updates for PR review. * Fixing missing const on the FrameAttachment* in Pass's call to FindAttachment() * Taa WIP - Adding filtering to both the current pixel and history. Adding rectification based on variance clipping. Adding some basic anti-flickering. Removing rejection based on depth. * Updates from PR code review. Mostly better commenting and naming. * Adding contrast adaptive sharpening based on AMD FidelityFX CAS to help with the softness added by TAA. * Changing to using luminance for sharpening instead of just green. Added some comments. * Moving Taa's NaN check to a better location. Disabling TAA and sharpening in prep for check in. * Updates from PR feedback. --- .../Passes/ContrastAdaptiveSharpening.pass | 75 +++++ .../Common/Assets/Passes/MainPipeline.pass | 7 + .../Assets/Passes/MeshMotionVector.pass | 39 +-- .../Assets/Passes/MotionVectorParent.pass | 20 ++ .../Assets/Passes/PassTemplates.azasset | 8 + .../Assets/Passes/PostProcessParent.pass | 52 +++- .../Passes/SMAA1xApplyLinearHDRColor.pass | 6 + .../Feature/Common/Assets/Passes/Taa.pass | 113 ++++++++ .../MotionVector/CameraMotionVector.azsl | 21 +- .../MotionVector/MeshMotionVectorCommon.azsli | 4 + .../ContrastAdaptiveSharpening.azsl | 85 ++++++ .../ContrastAdaptiveSharpening.shader | 11 + .../Assets/Shaders/PostProcessing/Taa.azsl | 271 ++++++++++++++++++ .../Assets/Shaders/PostProcessing/Taa.shader | 11 + .../atom_feature_common_asset_files.cmake | 2 + .../Code/Source/CommonSystemComponent.cpp | 5 + .../Code/Source/PostProcessing/TaaPass.cpp | 247 ++++++++++++++++ .../Code/Source/PostProcessing/TaaPass.h | 105 +++++++ .../Code/atom_feature_common_files.cmake | 2 + .../Atom/RHI/FrameGraphAttachmentInterface.h | 6 + .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 4 +- .../Atom/RPI.Public/Pass/PassAttachment.h | 3 +- .../RPI/Code/Include/Atom/RPI.Public/View.h | 16 +- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 29 +- .../Source/RPI.Public/Pass/PassAttachment.cpp | 4 +- Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp | 85 +++--- 26 files changed, 1139 insertions(+), 92 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/ContrastAdaptiveSharpening.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Passes/Taa.pass create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.shader create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.azsl create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.shader create mode 100644 Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ContrastAdaptiveSharpening.pass b/Gems/Atom/Feature/Common/Assets/Passes/ContrastAdaptiveSharpening.pass new file mode 100644 index 0000000000..44ab6f4a52 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/ContrastAdaptiveSharpening.pass @@ -0,0 +1,75 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "ContrastAdaptiveSharpeningTemplate", + "PassClass": "ComputePass", + "Slots": [ + { + "Name": "InputColor", + "SlotType": "Input", + "ShaderInputName": "m_inputColor", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "OutputColor", + "SlotType": "Output", + "ShaderInputName": "m_outputColor", + "ScopeAttachmentUsage": "Shader" + } + ], + "ImageAttachments": [ + { + "Name": "Output", + "FormatSource": { + "Pass": "This", + "Attachment": "InputColor" + }, + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "InputColor" + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT", + "BindFlags": "3", + "SharedQueueMask": "1" + } + } + ], + "Connections": [ + { + "LocalSlot": "OutputColor", + "AttachmentRef": { + "Pass": "This", + "Attachment": "Output" + } + } + ], + "FallbackConnections": [ + { + "Input": "InputColor", + "Output": "OutputColor" + } + ], + "PassData": { + "$type": "ComputePassData", + "ShaderAsset": { + "FilePath": "Shaders/Postprocessing/ContrastAdaptiveSharpening.shader" + }, + "Make Fullscreen Pass": true, + "ShaderDataMappings": { + "FloatMappings": [ + { + "Name": "m_strength", + "Value": 0.25 + } + ] + } + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass index af7408b48c..b2e0cf088e 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass @@ -341,6 +341,13 @@ "Attachment": "Depth" } }, + { + "LocalSlot": "MotionVectors", + "AttachmentRef": { + "Pass": "MotionVectorPass", + "Attachment": "MotionVectorOutput" + } + }, { "LocalSlot": "SwapChainOutput", "AttachmentRef": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MeshMotionVector.pass b/Gems/Atom/Feature/Common/Assets/Passes/MeshMotionVector.pass index 57600440b4..4c14fd9b3f 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MeshMotionVector.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MeshMotionVector.pass @@ -13,22 +13,11 @@ "SlotType": "Input", "ScopeAttachmentUsage": "InputAssembly" }, - // Outputs... + // Input/Output... { - "Name": "Output", - "SlotType": "Output", - "ScopeAttachmentUsage": "RenderTarget", - "LoadStoreAction": { - "ClearValue": { - "Value": [ - 0.0, - 0.0, - 0.0, - {} - ] - }, - "LoadAction": "Clear" - } + "Name": "MotionInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" }, { "Name": "OutputDepthStencil", @@ -46,19 +35,6 @@ } ], "ImageAttachments": [ - { - "Name": "MotionBuffer", - "SizeSource": { - "Source": { - "Pass": "Parent", - "Attachment": "SwapChainOutput" - } - }, - "ImageDescriptor": { - "Format": "R16G16_FLOAT", - "SharedQueueMask": "Graphics" - } - }, { "Name": "DepthStencil", "SizeSource": { @@ -74,13 +50,6 @@ } ], "Connections": [ - { - "LocalSlot": "Output", - "AttachmentRef": { - "Pass": "This", - "Attachment": "MotionBuffer" - } - }, { "LocalSlot": "OutputDepthStencil", "AttachmentRef": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MotionVectorParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/MotionVectorParent.pass index a8369e4618..d7f4894706 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MotionVectorParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MotionVectorParent.pass @@ -20,6 +20,19 @@ { "Name": "SwapChainOutput", "SlotType": "InputOutput" + }, + { + "Name": "MotionVectorOutput", + "SlotType": "Output" + } + ], + "Connections": [ + { + "LocalSlot": "MotionVectorOutput", + "AttachmentRef": { + "Pass": "MeshMotionVectorPass", + "Attachment": "MotionInputOutput" + } } ], "PassRequests": [ @@ -50,6 +63,13 @@ "Pass": "Parent", "Attachment": "SkinnedMeshes" } + }, + { + "LocalSlot": "MotionInputOutput", + "AttachmentRef": { + "Pass": "CameraMotionVectorPass", + "Attachment": "Output" + } } ], "PassData": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset index c56e8932b1..702ac8fe72 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset +++ b/Gems/Atom/Feature/Common/Assets/Passes/PassTemplates.azasset @@ -284,6 +284,14 @@ "Name": "SMAA1xApplyPerceptualColorTemplate", "Path": "Passes/SMAA1xApplyPerceptualColor.pass" }, + { + "Name": "TaaTemplate", + "Path": "Passes/Taa.pass" + }, + { + "Name": "ContrastAdaptiveSharpeningTemplate", + "Path": "Passes/ContrastAdaptiveSharpening.pass" + }, { "Name": "SsaoParentTemplate", "Path": "Passes/SsaoParent.pass" diff --git a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass index 36f7f1e985..fb27770da3 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/PostProcessParent.pass @@ -16,6 +16,10 @@ "Name": "Depth", "SlotType": "Input" }, + { + "Name": "MotionVectors", + "SlotType": "Input" + }, // SwapChain here is only used to reference the frame height and format { "Name": "SwapChainOutput", @@ -40,8 +44,8 @@ { "LocalSlot": "Output", "AttachmentRef": { - "Pass": "LightAdaptation", - "Attachment": "Output" + "Pass": "ContrastAdaptiveSharpeningPass", + "Attachment": "OutputColor" } }, { @@ -80,6 +84,34 @@ } ] }, + { + "Name": "TaaPass", + "TemplateName": "TaaTemplate", + "Enabled": false, + "Connections": [ + { + "LocalSlot": "InputColor", + "AttachmentRef": { + "Pass": "SMAA1xApplyLinearHDRColorPass", + "Attachment": "OutputColor" + } + }, + { + "LocalSlot": "InputDepth", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "Depth" + } + }, + { + "LocalSlot": "MotionVectors", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "MotionVectors" + } + } + ] + }, { "Name": "DepthOfFieldPass", "TemplateName": "DepthOfFieldTemplate", @@ -88,7 +120,7 @@ { "LocalSlot": "DoFColorInput", "AttachmentRef": { - "Pass": "SMAA1xApplyLinearHDRColorPass", + "Pass": "TaaPass", "Attachment": "OutputColor" } }, @@ -134,6 +166,20 @@ } } ] + }, + { + "Name": "ContrastAdaptiveSharpeningPass", + "TemplateName": "ContrastAdaptiveSharpeningTemplate", + "Enabled": false, + "Connections": [ + { + "LocalSlot": "InputColor", + "AttachmentRef": { + "Pass": "LightAdaptation", + "Attachment": "Output" + } + } + ] } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass index 98700d5f0c..70604fba25 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SMAA1xApplyLinearHDRColor.pass @@ -40,6 +40,12 @@ } } ], + "FallbackConnections": [ + { + "Input": "InputColor", + "Output": "OutputColor" + } + ], "PassRequests": [ { "Name": "SMAAConvertToPerceptualColor", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/Taa.pass b/Gems/Atom/Feature/Common/Assets/Passes/Taa.pass new file mode 100644 index 0000000000..f1ba156007 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/Taa.pass @@ -0,0 +1,113 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "PassAsset", + "ClassData": { + "PassTemplate": { + "Name": "TaaTemplate", + "PassClass": "TaaPass", + "Slots": [ + { + "Name": "InputColor", + "SlotType": "Input", + "ShaderInputName": "m_inputColor", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "InputDepth", + "SlotType": "Input", + "ShaderInputName": "m_inputDepth", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "MotionVectors", + "SlotType": "Input", + "ShaderInputName": "m_motionVectors", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "LastFrameAccumulation", + "SlotType": "Input", + "ShaderInputName": "m_lastFrameAccumulation", + "ScopeAttachmentUsage": "Shader" + }, + { + "Name": "OutputColor", + "SlotType": "Output", + "ShaderInputName": "m_outputColor", + "ScopeAttachmentUsage": "Shader" + } + ], + "ImageAttachments": [ + { + "Name": "Accumulation1", + "Lifetime": "Imported", + "FormatSource": { + "Pass": "This", + "Attachment": "InputColor" + }, + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "InputColor" + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT", + "BindFlags": "3", + "SharedQueueMask": "1" + } + }, + { + "Name": "Accumulation2", + "Lifetime": "Imported", + "FormatSource": { + "Pass": "This", + "Attachment": "InputColor" + }, + "SizeSource": { + "Source": { + "Pass": "This", + "Attachment": "InputColor" + } + }, + "ImageDescriptor": { + "Format": "R16G16B16A16_FLOAT", + "BindFlags": "3", + "SharedQueueMask": "1" + } + } + ], + "FallbackConnections": [ + { + "Input": "InputColor", + "Output": "OutputColor" + } + ], + "PassData": { + "$type": "TaaPassData", + "ShaderAsset": { + "FilePath": "Shaders/Postprocessing/Taa.shader" + }, + "Make Fullscreen Pass": true, + "ShaderDataMappings": { + "FloatMappings": [ + { + "Name": "m_currentFrameContribution", + "Value": 0.1 + }, + { + "Name": "m_clampGamma", + "Value": 1.0 + }, + { + "Name": "m_maxDeviationBeforeDampening", + "Value": 0.5 + } + ] + }, + "NumJitterPositions": 16 + } + } + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/CameraMotionVector.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/CameraMotionVector.azsl index a073f42f03..c83e5138e6 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/CameraMotionVector.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/CameraMotionVector.azsl @@ -39,10 +39,27 @@ PSOutput MainPS(VSOutput IN) PSOutput OUT; float depth = PassSrg::m_depthStencil.Sample(PassSrg::LinearSampler, IN.m_texCoord).r; + + // If depth is 0, that means depth is on the far plane. This should be treated as being infinitely far + // away, not actually on the far plane, because the infinitely far background shouldn't move as a result + // of camera translation. Tweaking the depth to -near/far distance makes that happen. Keep in mind near + // and far are inverted, so this normally a very small value. + if (depth == 0.0) + { + depth = -ViewSrg::GetFarZ() / ViewSrg::GetNearZ(); + } + float2 clipPos = float2(mad(IN.m_texCoord.x, 2.0, -1.0), mad(IN.m_texCoord.y, -2.0, 1.0)); float4 worldPos = mul(ViewSrg::m_viewProjectionInverseMatrix, float4(clipPos, depth, 1.0)); + float4 clipPosPrev = mul(ViewSrg::m_viewProjectionPrevMatrix, float4((worldPos / worldPos.w).xyz, 1.0)); - - OUT.m_motion = (clipPos - (clipPosPrev / clipPosPrev.w).xy) * 0.5; + clipPosPrev = (clipPosPrev / clipPosPrev.w); + + // Clip space is from -1.0 to 1.0, so the motion vectors are 2x as big as they should be + OUT.m_motion = (clipPos - clipPosPrev.xy) * 0.5; + + // Flip y to line up with uv coordinates + OUT.m_motion.y = -OUT.m_motion.y; + return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli index c11e9d9e0e..ff2758af87 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/MotionVector/MeshMotionVectorCommon.azsli @@ -41,5 +41,9 @@ PSOutput MainPS(VSOutput IN) float2 motion = (clipPos.xy / clipPos.w - clipPosPrev.xy / clipPosPrev.w) * 0.5; OUT.m_motion = motion; + + // Flip y to line up with uv coordinates + OUT.m_motion.y = -OUT.m_motion.y; + return OUT; } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.azsl new file mode 100644 index 0000000000..14fa942a7d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.azsl @@ -0,0 +1,85 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +#define TILE_DIM_X 16 +#define TILE_DIM_Y 16 + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_inputColor; + RWTexture2D m_outputColor; + + float m_strength; // Strength of the sharpening effect. Range from 0 to 1. +} + + +// Constrast Adaptive Sharpening, based on AMD FidelityFX CAS - https://gpuopen.com/fidelityfx-cas/ + +// This shader sharpens the input based on the contrast of the local neighborhood +// so that only areas that need sharpening are sharpened, while high constast areas +// are mostly left alone. + +[numthreads(TILE_DIM_X, TILE_DIM_Y, 1)] +void MainCS( + uint3 dispatchThreadID : SV_DispatchThreadID, + uint3 groupID : SV_GroupID, + uint groupIndex : SV_GroupIndex) +{ + uint2 pixelCoord = dispatchThreadID.xy; + + // Fetch local neighborhood to determin sharpening weight. + // a + // b c d + // e + + float3 sampleA = PassSrg::m_inputColor[pixelCoord + int2( 0, -1)].rgb; + float3 sampleB = PassSrg::m_inputColor[pixelCoord + int2(-1, 0)].rgb; + float3 sampleC = PassSrg::m_inputColor[pixelCoord + int2( 0, 0)].rgb; + float3 sampleD = PassSrg::m_inputColor[pixelCoord + int2( 1, 0)].rgb; + float3 sampleE = PassSrg::m_inputColor[pixelCoord + int2( 0, 1)].rgb; + + float lumA = GetLuminance(sampleA); + float lumB = GetLuminance(sampleB); + float lumC = GetLuminance(sampleC); + float lumD = GetLuminance(sampleD); + float lumE = GetLuminance(sampleE); + + // Get the min and max. Just use the green channel for luminance. + float minLum = min(min(lumA, lumB), min(lumC, min(lumD, lumE))); + float maxLum = max(max(lumA, lumB), max(lumC, max(lumD, lumE))); + + float dMinLum = minLum; // Distance from 0 to minimum + float dMaxLum = 1.0 - maxLum; // Distance from 1 to the maximum + + // baseSharpening is higher when local contrast is lower to avoid over-sharpening. + float baseSharpening = min(dMinLum, dMaxLum) / max(maxLum, 0.0001); + baseSharpening = sqrt(baseSharpening); // bias towards more sharpening + + // Negative weights for sharpening effect, center pixel is always weighted 1. + float developerMaximum = lerp(-0.125, -0.2, PassSrg::m_strength); + float weight = baseSharpening * developerMaximum; + float totalWeight = weight * 4 + 1.0; + + float3 output = + ( + sampleA * weight + + sampleB * weight + + sampleC + + sampleD * weight + + sampleE * weight + ) / totalWeight; + + PassSrg::m_outputColor[pixelCoord] = float4(output, 1.0); +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.shader new file mode 100644 index 0000000000..756ce0ec7a --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/ContrastAdaptiveSharpening.shader @@ -0,0 +1,11 @@ +{ + "Source": "ContrastAdaptiveSharpening", + "ProgramSettings": { + "EntryPoints": [ + { + "name": "MainCS", + "type": "Compute" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.azsl new file mode 100644 index 0000000000..94944df9de --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.azsl @@ -0,0 +1,271 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +#define TILE_DIM_X 16 +#define TILE_DIM_Y 16 + +ShaderResourceGroup PassSrg : SRG_PerPass +{ + Texture2D m_inputColor; + Texture2D m_inputDepth; + Texture2D m_motionVectors; + Texture2D m_lastFrameAccumulation; + + RWTexture2D m_outputColor; + + Sampler LinearSampler + { + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; + }; + + // Current frame's default contribution to the history. + float m_currentFrameContribution; + + // Increase this value for weaker clamping, decrease for stronger clamping, default 1.0. + float m_clampGamma; + + // Default 0.5, used for flicker reduction. Any sample further than this many standard deviations outside the neighborhood + // will have its weight decreased. The further outside the max deviation, the more its weight is reduced. + float m_maxDeviationBeforeDampening; + + struct Constants + { + uint2 m_inputColorSize; + float2 m_inputColorRcpSize; + + // 3x3 filter weights + // 8 2 6 + // 3 0 1 + // 7 4 5 + float4 m_weights1; // 0 1 2 3 + float4 m_weights2; // 4 5 6 7 + float4 m_weights3; // 8 x x x + }; + Constants m_constantData; +} + +static const int2 offsets[9] = +{ + // Center + int2(0, 0), + // Cross + int2( 1, 0), + int2( 0,-1), + int2(-1, 0), + int2( 0, 1), + // Diagonals + int2( 1,-1), + int2( 1, 1), + int2(-1,-1), + int2(-1, 1), +}; + +float3 RgbToYCoCg(float3 rgb) +{ + const float3x3 conversionMatrix = + { + 0.25, 0.50, 0.25, + 0.50, 0.00, -0.50, + -0.25, 0.50, -0.25 + }; + return mul(conversionMatrix, rgb); +} + +float3 YCoCgToRgb(float3 yCoCg) +{ + const float3x3 conversionMatrix = + { + 1.0, 1.0, -1.0, + 1.0, 0.0, 1.0, + 1.0, -1.0, -1.0 + }; + return mul(conversionMatrix, yCoCg); +} + +// Sample a texture with a 5 tap Catmull-Rom. Consider ripping this out and putting in a more general location. +// This function samples a 4x4 neighborhood around the uv. By taking advantage of bilinear filtering this can be +// done with only 9 taps on the edges between pixels. The cost is further reduced by dropping the 4 diagonal +// samples as their influence is negligible. +float4 SampleCatmullRom5Tap(Texture2D texture, SamplerState linearSampler, float2 uv, float2 textureSize, float2 rcpTextureSize, float sharpness) +{ + // Think of sample locations in the 4x4 neighborhood as having a top left coordinate of 0,0 and + // a bottom right coordinate of 3,3. + + // Find the position in texture space then round it to get the center of the 1,1 pixel (tc1) + float2 texelPos = uv * textureSize; + float2 tc1= floor(texelPos - 0.5) + 0.5; + + // Offset from center position to texel + float2 f = texelPos - tc1; + + // Compute Catmull-Rom weights based on the offset and sharpness + float c = sharpness; + float2 w0 = f * (-c + f * (2.0 * c - c * f)); + float2 w1 = 1.0 + f * f * (c -3.0 + (2.0 - c) * f); + float2 w2 = f * (c + f * ((3.0 - 2.0 * c) - (2.0 - c) * f)); + float2 w3 = f * f * (c * f - c); + + float2 w12 = w1 + w2; + + // Compute uv coordinates for sampling the texture + float2 tc0 = (tc1 - 1.0f) * rcpTextureSize; + float2 tc3 = (tc1 + 2.0f) * rcpTextureSize; + float2 tc12 = (tc1 + w2 / w12) * rcpTextureSize; + + // Compute sample weights + float sw0 = w12.x * w0.y; + float sw1 = w0.x * w12.y; + float sw2 = w12.x * w12.y; + float sw3 = w3.x * w12.y; + float sw4 = w12.x * w3.y; + + // total weight of samples to normalize result. + float totalWeight = sw0 + sw1 + sw2 + sw3 + sw4; + + float4 result = 0.0f; + result += texture.SampleLevel(linearSampler, float2(tc12.x, tc0.y), 0.0) * sw0; + result += texture.SampleLevel(linearSampler, float2( tc0.x, tc12.y), 0.0) * sw1; + result += texture.SampleLevel(linearSampler, float2(tc12.x, tc12.y), 0.0) * sw2; + result += texture.SampleLevel(linearSampler, float2( tc3.x, tc12.y), 0.0) * sw3; + result += texture.SampleLevel(linearSampler, float2(tc12.x, tc3.y), 0.0) * sw4; + + return result / totalWeight; +} + +[numthreads(TILE_DIM_X, TILE_DIM_Y, 1)] +void MainCS( + uint3 dispatchThreadID : SV_DispatchThreadID, + uint3 groupID : SV_GroupID, + uint groupIndex : SV_GroupIndex) +{ + uint2 pixelCoord = dispatchThreadID.xy; + + const float filterWeights[9] = + { + PassSrg::m_constantData.m_weights1.x, + PassSrg::m_constantData.m_weights1.y, + PassSrg::m_constantData.m_weights1.z, + PassSrg::m_constantData.m_weights1.w, + PassSrg::m_constantData.m_weights2.x, + PassSrg::m_constantData.m_weights2.y, + PassSrg::m_constantData.m_weights2.z, + PassSrg::m_constantData.m_weights2.w, + PassSrg::m_constantData.m_weights3.x, + }; + + float3 sum = 0.0; + float3 sumOfSquares = 0.0; + float nearestDepth = 1.0; + uint2 nearestDepthPixelCoord; + + float3 thisFrameColor = float3(0.0, 0.0, 0.0); + + // Sample the neighborhood to filter the current pixel, gather statistics about + // its neighbors, and find the closest neighbor to choose a motion vector. + [unroll] for (int i = 0; i < 9; ++i) + { + uint2 neighborhoodPixelCoord = pixelCoord + offsets[i]; + float3 neighborhoodColor = PassSrg::m_inputColor[neighborhoodPixelCoord].rgb; + + // Convert to YCoCg space for better clipping. + neighborhoodColor = RgbToYCoCg(neighborhoodColor); + + sum += neighborhoodColor; + sumOfSquares += neighborhoodColor * neighborhoodColor; + thisFrameColor += neighborhoodColor * filterWeights[i]; + + // Find the coordinate of the nearest depth + float neighborhoodDepth = PassSrg::m_inputDepth[neighborhoodPixelCoord].r; + if (neighborhoodDepth < nearestDepth) + { + nearestDepth = neighborhoodDepth; + nearestDepthPixelCoord = neighborhoodPixelCoord; + } + } + + // Variance clipping, see http://developer.download.nvidia.com/gameworks/events/GDC2016/msalvi_temporal_supersampling.pdf + float3 mean = sum / 9.0; + float3 standardDeviation = max(0.0, sqrt(sumOfSquares / 9.0 - mean * mean)); + standardDeviation *= PassSrg::m_clampGamma; + + // Grab the motion vector from the closest pixel in the 3x3 neighborhood. This is done so that motion vectors correctly + // track edges. For instance, if a pixel lies on the edge of a moving object, where the color is a blend of the + // forground and background, it's possible for the pixel center to hit the (not moving) background. However, the correct + // history for this pixel will be the location this edge was the previous frame. By choosing the motion of the nearest + // pixel in the neighborhood that edge will be correctly tracked. + + // Motion vectors store the direction of movement, so to look up where things were in the previous frame, it's negated. + float2 previousPositionOffset = -PassSrg::m_motionVectors[nearestDepthPixelCoord]; + + // Get the uv coordinate for the previous frame. + float2 rcpSize = PassSrg::m_constantData.m_inputColorRcpSize; + float2 uvCoord = (pixelCoord + 0.5f) * rcpSize; + float2 uvOld = uvCoord + previousPositionOffset; + float2 previousPositionOffsetInPixels = float2(PassSrg::m_constantData.m_inputColorSize) * previousPositionOffset; + + // Sample the last frame using a 5-tap Catmull-Rom + float3 lastFrameColor = SampleCatmullRom5Tap(PassSrg::m_lastFrameAccumulation, PassSrg::LinearSampler, uvOld, PassSrg::m_constantData.m_inputColorSize, PassSrg::m_constantData.m_inputColorRcpSize, 0.5).rgb; + lastFrameColor = RgbToYCoCg(lastFrameColor); + + // Last frame color relative to mean + float3 centerColorOffset = lastFrameColor - mean; + float3 colorOffsetStandardDeviationRatio = abs(standardDeviation / centerColorOffset); + + // Clamp the color by the aabb of the standardDeviation. Can never be greater than 1, so will always be inside or on the bounds of the aabb. + float clampedColorLength = min(min(min(1, colorOffsetStandardDeviationRatio.x), colorOffsetStandardDeviationRatio.y), colorOffsetStandardDeviationRatio.z); + + // Calculate the true clamped color by offsetting it back from the mean. + float3 lastFrameClampedColor = mean + centerColorOffset * clampedColorLength; + + // Anti-flickering - Reduce current frame weight the more it deviates from the history based on the standard deviation of the neighborhood. + // Start reducing weight at differences greater than m_maxDeviationBeforeDampening standard deviations in luminance. + float standardDeviationWeight = standardDeviation.r * PassSrg::m_maxDeviationBeforeDampening; + float3 sdFromLastFrame = standardDeviationWeight / abs(lastFrameClampedColor.r - thisFrameColor.r); + + float currentFrameWeight = PassSrg::m_currentFrameContribution; + currentFrameWeight *= saturate(sdFromLastFrame * sdFromLastFrame); + + // Back to Rgb space + thisFrameColor = YCoCgToRgb(thisFrameColor); + lastFrameClampedColor = YCoCgToRgb(lastFrameClampedColor); + + // Out of bounds protection. + if (any(uvOld > 1.0) || any(uvOld < 0.0)) + { + currentFrameWeight = 1.0f; + } + + // Blend should be in perceptual space, so tonemap first + float luminance = GetLuminance(thisFrameColor); + thisFrameColor = thisFrameColor / (1 + luminance); + lastFrameClampedColor = lastFrameClampedColor / (1 + luminance); + + // Blend color with history + float3 color = lerp(lastFrameClampedColor, thisFrameColor, currentFrameWeight); + + // Un-tonemap color + color = color * (1.0 + luminance); + + // NaN protection (without this NaNs could get in the history buffer and quickly consume the frame) + color = max(0.0, color); + + PassSrg::m_outputColor[pixelCoord].rgb = color; + +} diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.shader b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.shader new file mode 100644 index 0000000000..f30ff92f20 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Shaders/PostProcessing/Taa.shader @@ -0,0 +1,11 @@ +{ + "Source": "Taa", + "ProgramSettings": { + "EntryPoints": [ + { + "name": "MainCS", + "type": "Compute" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake index a9ba765329..3dfabc586a 100644 --- a/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake +++ b/Gems/Atom/Feature/Common/Assets/atom_feature_common_asset_files.cmake @@ -89,6 +89,7 @@ set(FILES Passes/CascadedShadowmaps.pass Passes/CheckerboardResolveColor.pass Passes/CheckerboardResolveDepth.pass + Passes/ContrastAdaptiveSharpening.pass Passes/ConvertToAcescg.pass Passes/DebugOverlayParent.pass Passes/DeferredFog.pass @@ -207,6 +208,7 @@ set(FILES Passes/SsaoHalfRes.pass Passes/SsaoParent.pass Passes/SubsurfaceScattering.pass + Passes/Taa.pass Passes/Transparent.pass Passes/TransparentParent.pass Passes/UI.pass diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index d38db1b08e..af28624357 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,7 @@ namespace AZ PostProcessFeatureProcessor::Reflect(context); ImGuiPassData::Reflect(context); RayTracingPassData::Reflect(context); + TaaPassData::Reflect(context); LightingPreset::Reflect(context); ModelPreset::Reflect(context); @@ -230,6 +232,9 @@ namespace AZ // Add Depth Downsample/Upsample passes passSystem->AddPassCreator(Name("DepthUpsamplePass"), &DepthUpsamplePass::Create); + + // Add Taa Pass + passSystem->AddPassCreator(Name("TaaPass"), &TaaPass::Create); // Add DepthOfField pass passSystem->AddPassCreator(Name("DepthOfFieldCompositePass"), &DepthOfFieldCompositePass::Create); diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp new file mode 100644 index 0000000000..9f885ede70 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.cpp @@ -0,0 +1,247 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::Render +{ + + RPI::Ptr TaaPass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew TaaPass(descriptor); + return pass; + } + + TaaPass::TaaPass(const RPI::PassDescriptor& descriptor) + : Base(descriptor) + { + uint32_t numJitterPositions = 8; + + const TaaPassData* taaPassData = RPI::PassUtils::GetPassData(descriptor); + if (taaPassData) + { + numJitterPositions = taaPassData->m_numJitterPositions; + } + + // The coprimes 2, 3 are commonly used for halton sequences because they have an even distribution even for + // few samples. With larger primes you need to offset by some amount between each prime to have the same + // effect. We could allow this to be configurable in the future. + SetupSubPixelOffsets(2, 3, numJitterPositions); + } + + void TaaPass::CompileResources(const RHI::FrameGraphCompileContext& context) + { + struct TaaConstants + { + AZStd::array m_size = { 1, 1 }; + AZStd::array m_rcpSize = { 0.0, 0.0 }; + + AZStd::array m_weights1 = { 0.0 }; + AZStd::array m_weights2 = { 0.0 }; + AZStd::array m_weights3 = { 0.0 }; + }; + + TaaConstants cb; + RHI::Size inputSize = m_lastFrameAccumulationBinding->m_attachment->m_descriptor.m_image.m_size; + cb.m_size[0] = inputSize.m_width; + cb.m_size[1] = inputSize.m_height; + cb.m_rcpSize[0] = 1.0f / inputSize.m_width; + cb.m_rcpSize[1] = 1.0f / inputSize.m_height; + + Offset jitterOffset = m_subPixelOffsets.at(m_offsetIndex); + GenerateFilterWeights(Vector2(jitterOffset.m_xOffset, jitterOffset.m_yOffset)); + cb.m_weights1 = { m_filterWeights[0], m_filterWeights[1], m_filterWeights[2], m_filterWeights[3] }; + cb.m_weights2 = { m_filterWeights[4], m_filterWeights[5], m_filterWeights[6], m_filterWeights[7] }; + cb.m_weights3 = { m_filterWeights[8], 0.0f, 0.0f, 0.0f }; + + m_shaderResourceGroup->SetConstant(m_constantDataIndex, cb); + + + Base::CompileResources(context); + } + + void TaaPass::FrameBeginInternal(FramePrepareParams params) + { + RHI::Size inputSize = m_inputColorBinding->m_attachment->m_descriptor.m_image.m_size; + Vector2 rcpInputSize = Vector2(1.0 / inputSize.m_width, 1.0 / inputSize.m_height); + + RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView(); + m_offsetIndex = (m_offsetIndex + 1) % m_subPixelOffsets.size(); + Offset offset = m_subPixelOffsets.at(m_offsetIndex); + view->SetClipSpaceOffset(offset.m_xOffset * rcpInputSize.GetX(), offset.m_yOffset * rcpInputSize.GetY()); + + m_lastFrameAccumulationBinding->SetAttachment(m_accumulationAttachments[m_accumulationOuptutIndex]); + m_accumulationOuptutIndex ^= 1; // swap which attachment is the output and last frame + + UpdateAttachmentImage(m_accumulationAttachments[m_accumulationOuptutIndex]); + m_outputColorBinding->SetAttachment(m_accumulationAttachments[m_accumulationOuptutIndex]); + + Base::FrameBeginInternal(params); + } + + void TaaPass::ResetInternal() + { + m_accumulationAttachments[0].reset(); + m_accumulationAttachments[1].reset(); + + m_inputColorBinding = nullptr; + m_lastFrameAccumulationBinding = nullptr; + m_outputColorBinding = nullptr; + + Base::ResetInternal(); + } + + void TaaPass::BuildAttachmentsInternal() + { + m_accumulationAttachments[0] = FindAttachment(Name("Accumulation1")); + m_accumulationAttachments[1] = FindAttachment(Name("Accumulation2")); + + bool hasAttachments = m_accumulationAttachments[0] || m_accumulationAttachments[1]; + AZ_Error("TaaPass", hasAttachments, "TaaPass must have Accumulation1 and Accumulation2 ImageAttachments defined."); + + if (hasAttachments) + { + // Make sure the attachments have images when the pass first loads. + for (auto i : { 0, 1 }) + { + if (!m_accumulationAttachments[i]->m_importedResource) + { + UpdateAttachmentImage(m_accumulationAttachments[i]); + } + } + } + + m_inputColorBinding = FindAttachmentBinding(Name("InputColor")); + AZ_Error("TaaPass", m_inputColorBinding, "TaaPass requires a slot for InputColor."); + m_lastFrameAccumulationBinding = FindAttachmentBinding(Name("LastFrameAccumulation")); + AZ_Error("TaaPass", m_lastFrameAccumulationBinding, "TaaPass requires a slot for LastFrameAccumulation."); + m_outputColorBinding = FindAttachmentBinding(Name("OutputColor")); + AZ_Error("TaaPass", m_outputColorBinding, "TaaPass requires a slot for OutputColor."); + + // Set up the attachment for last frame accumulation and output color if it's never been done to + // ensure SRG indices are set up correctly by the pass system. + if (m_lastFrameAccumulationBinding->m_attachment == nullptr) + { + m_lastFrameAccumulationBinding->SetAttachment(m_accumulationAttachments[0]); + m_outputColorBinding->SetAttachment(m_accumulationAttachments[1]); + } + + Base::BuildAttachmentsInternal(); + } + + void TaaPass::UpdateAttachmentImage(RPI::Ptr& attachment) + { + if (!attachment) + { + return; + } + + // update the image attachment descriptor to sync up size and format + attachment->Update(true); + RHI::ImageDescriptor& imageDesc = attachment->m_descriptor.m_image; + RPI::AttachmentImage* currentImage = azrtti_cast(attachment->m_importedResource.get()); + + if (attachment->m_importedResource && imageDesc.m_size == currentImage->GetDescriptor().m_size) + { + // If there's a resource already and the size didn't change, just keep using the old AttachmentImage. + return; + } + + Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + + // set the bind flags + imageDesc.m_bindFlags |= RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderReadWrite; + + // The ImageViewDescriptor must be specified to make sure the frame graph compiler doesn't treat this as a transient image. + RHI::ImageViewDescriptor viewDesc = RHI::ImageViewDescriptor::Create(imageDesc.m_format, 0, 0); + viewDesc.m_aspectFlags = RHI::ImageAspectFlags::Color; + viewDesc.m_overrideBindFlags = RHI::ImageBindFlags::ShaderReadWrite; + + // The full path name is needed for the attachment image so it's not deduplicated from accumulation images in different pipelines. + AZStd::string imageName = RPI::ConcatPassString(GetPathName(), attachment->m_path); + auto attachmentImage = RPI::AttachmentImage::Create(*pool.get(), imageDesc, Name(imageName), nullptr, &viewDesc); + + attachment->m_path = attachmentImage->GetAttachmentId(); + attachment->m_importedResource = attachmentImage; + } + + void TaaPass::SetupSubPixelOffsets(uint32_t haltonX, uint32_t haltonY, uint32_t length) + { + m_subPixelOffsets.resize(length); + HaltonSequence<2> sequence = HaltonSequence<2>({haltonX, haltonY}); + sequence.FillHaltonSequence(m_subPixelOffsets.begin(), m_subPixelOffsets.end()); + + // Adjust to the -1.0 to 1.0 range. This is done because the view needs offsets in clip + // space and is one less calculation that would need to be done in FrameBeginInternal() + AZStd::for_each(m_subPixelOffsets.begin(), m_subPixelOffsets.end(), + [](Offset& offset) + { + offset.m_xOffset = 2.0f * offset.m_xOffset - 1.0f; + offset.m_yOffset = 2.0f * offset.m_yOffset - 1.0f; + } + ); + } + + // Approximation of a Blackman Harris window function of width 3.3. + // https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window + static float BlackmanHarris(AZ::Vector2 uv) + { + return expf(-2.29f * (uv.GetX() * uv.GetX() + uv.GetY() * uv.GetY())); + } + + // Generates filter weights for the 3x3 neighborhood of a pixel. Since jitter positions are the + // same for every pixel we can calculate this once here and upload to the SRG. + // Jitter weights are based on a window function centered at the pixel center (we use Blackman-Harris). + // As the jitter position moves around, some neighborhood locations decrease in weight, and others + // increase in weight based on their distance from the center of the pixel. + void TaaPass::GenerateFilterWeights(AZ::Vector2 jitterOffset) + { + static const AZStd::array pixelOffsets = + { + // Center + Vector2(0.0f, 0.0f), + // Cross + Vector2( 1.0f, 0.0f), + Vector2( 0.0f, 1.0f), + Vector2(-1.0f, 0.0f), + Vector2( 0.0f, -1.0f), + // Diagonals + Vector2( 1.0f, 1.0f), + Vector2( 1.0f, -1.0f), + Vector2(-1.0f, 1.0f), + Vector2(-1.0f, -1.0f), + }; + + float sum = 0.0f; + for (uint32_t i = 0; i < 9; ++i) + { + m_filterWeights[i] = BlackmanHarris(pixelOffsets[i] + jitterOffset); + sum += m_filterWeights[i]; + } + + // Normalize the weight so the sum of all weights is 1.0. + float normalization = 1.0f / sum; + for (uint32_t i = 0; i < 9; ++i) + { + m_filterWeights[i] *= normalization; + } + } + +} // namespace AZ::Render diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h new file mode 100644 index 0000000000..6133720691 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/TaaPass.h @@ -0,0 +1,105 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include + +namespace AZ::Render +{ + //! Custom data for the Taa Pass. + struct TaaPassData + : public RPI::ComputePassData + { + AZ_RTTI(TaaPassData, "{BCDF5C7D-7A78-4C69-A460-FA6899C3B960}", ComputePassData); + AZ_CLASS_ALLOCATOR(TaaPassData, SystemAllocator, 0); + + TaaPassData() = default; + virtual ~TaaPassData() = default; + + static void Reflect(ReflectContext* context) + { + if (auto* serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(1) + ->Field("NumJitterPositions", &TaaPassData::m_numJitterPositions) + ; + } + } + + uint32_t m_numJitterPositions = 8; + }; + + class TaaPass : public RPI::ComputePass + { + using Base = RPI::ComputePass; + AZ_RPI_PASS(TaaPass); + + public: + AZ_RTTI(AZ::Render::TaaPass, "{AB3BD4EA-33D7-477F-82B4-21DDFB517499}", Base); + AZ_CLASS_ALLOCATOR(TaaPass, SystemAllocator, 0); + virtual ~TaaPass() = default; + + /// Creates a TaaPass + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + private: + + TaaPass(const RPI::PassDescriptor& descriptor); + + // Scope producer functions... + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + + // Pass behavior overrides... + void FrameBeginInternal(FramePrepareParams params) override; + void ResetInternal() override; + void BuildAttachmentsInternal() override; + + void UpdateAttachmentImage(RPI::Ptr& attachment); + + void SetupSubPixelOffsets(uint32_t haltonX, uint32_t haltonY, uint32_t length); + void GenerateFilterWeights(AZ::Vector2 jitterOffset); + + RHI::ShaderInputNameIndex m_outputIndex = "m_output"; + RHI::ShaderInputNameIndex m_lastFrameAccumulationIndex = "m_lastFrameAccumulation"; + RHI::ShaderInputNameIndex m_constantDataIndex = "m_constantData"; + + Data::Instance m_accumulationAttachments[2]; + + RPI::PassAttachmentBinding* m_inputColorBinding = nullptr; + RPI::PassAttachmentBinding* m_lastFrameAccumulationBinding = nullptr; + RPI::PassAttachmentBinding* m_outputColorBinding = nullptr; + + struct Offset + { + Offset() = default; + + // Constructor for implicit conversion from array output by HaltonSequence. + Offset(AZStd::array offsets) + : m_xOffset(offsets[0]) + , m_yOffset(offsets[1]) + {}; + + float m_xOffset = 0.0f; + float m_yOffset = 0.0f; + }; + + AZStd::array m_filterWeights = { 0.0f }; + + AZStd::vector m_subPixelOffsets; + uint32_t m_offsetIndex = 0; + + uint8_t m_accumulationOuptutIndex = 0; + + }; +} // namespace AZ::Render diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index a108fc82f5..a759de77fa 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -252,6 +252,8 @@ set(FILES Source/PostProcessing/SsaoPasses.h Source/PostProcessing/SubsurfaceScatteringPass.cpp Source/PostProcessing/SubsurfaceScatteringPass.h + Source/PostProcessing/TaaPass.h + Source/PostProcessing/TaaPass.cpp Source/RayTracing/RayTracingFeatureProcessor.h Source/RayTracing/RayTracingFeatureProcessor.cpp Source/RayTracing/RayTracingAccelerationStructurePass.cpp diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameGraphAttachmentInterface.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameGraphAttachmentInterface.h index c3194efbb6..af29079a97 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameGraphAttachmentInterface.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FrameGraphAttachmentInterface.h @@ -89,6 +89,12 @@ namespace AZ return m_attachmentDatabase.IsAttachmentValid(attachmentId); } + //! Returns the FrameAttachment for a given AttachmentId, or nullptr if not found. + const FrameAttachment* FindAttachment(const AttachmentId& attachmentId) const + { + return m_attachmentDatabase.FindAttachment(attachmentId); + } + //! Resolves an attachment id to a buffer descriptor. This is useful when accessing buffer information for //! an attachment that was declared in a different scope. //! \param attachmentId The attachment id used to lookup the descriptors. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 1cba71ae7e..3d0a8cd3a8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -184,8 +184,8 @@ namespace AZ //! Collect all different view tags from this pass virtual void GetPipelineViewTags(SortedPipelineViewTags& outTags) const; - //! Adds this pass' DrawListTags to the outDrawListMask. - virtual void GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, PassesByDrawList& outPassesByDrawList, const PipelineViewTag& viewTag) const; + //! Adds this pass' DrawListTags to the outDrawListMask. + virtual void GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, PassesByDrawList& outPassesByDrawList, const PipelineViewTag& viewTag) const; //! Check if the pass has a DrawListTag. Pass' DrawListTag can be used to filter draw items. virtual RHI::DrawListTag GetDrawListTag() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h index 5509398f55..fd2a49a941 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassAttachment.h @@ -52,7 +52,8 @@ namespace AZ const RHI::TransientBufferDescriptor GetTransientBufferDescriptor() const; //! Updates the size and format of this attachment using the sources below if specified - void Update(); + //! @param updateImportedAttachments - Imported attchments will only update if this is true. + void Update(bool updateImportedAttachments = false); //! Sets all formats to nearest device supported formats and warns if changes where made void ValidateDeviceFormats(const AZStd::vector& formatFallbacks, RHI::FormatCapabilities capabilities = RHI::FormatCapabilities::None); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index e611ecf0d6..fabec8d896 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -88,6 +88,9 @@ namespace AZ //! Sets the viewToClip matrix and recalculates the other matrices void SetViewToClipMatrix(const AZ::Matrix4x4& viewToClip); + //! Sets a pixel offset on the view, usually used for jittering the camera for anti-aliasing techniques. + void SetClipSpaceOffset(float xOffset, float yOffset); + const AZ::Matrix4x4& GetWorldToViewMatrix() const; //! Use GetViewToWorldMatrix().GetTranslation() to get the camera's position. const AZ::Matrix4x4& GetViewToWorldMatrix() const; @@ -173,7 +176,6 @@ namespace AZ Matrix4x4 m_worldToViewMatrix; Matrix4x4 m_viewToWorldMatrix; Matrix4x4 m_viewToClipMatrix; - Matrix4x4 m_clipToViewMatrix; Matrix4x4 m_clipToWorldMatrix; // View's position in world space @@ -188,17 +190,15 @@ namespace AZ // Cached matrix to transform from world space to clip space Matrix4x4 m_worldToClipMatrix; - Matrix4x4 m_worldToClipPrevMatrix; + Matrix4x4 m_worldToViewPrevMatrix; + Matrix4x4 m_viewToClipPrevMatrix; + + // Clip space offset for camera jitter with taa + Vector2 m_clipSpaceOffset = Vector2(0.0f, 0.0f); // Flags whether view matrices are dirty which requires rebuild srg bool m_needBuildSrg = true; - // Following two bools form a delay circuit to update history of next frame - // if vp matrix is changed during current frame, this is required because - // view class doesn't contain subroutines called at the end of each frame - bool m_worldToClipMatrixChanged = true; - bool m_worldToClipPrevMatrixNeedsUpdate = false; - MatrixChangedEvent m_onWorldToClipMatrixChange; MatrixChangedEvent m_onWorldToViewMatrixChange; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 8d613eb2bb..1e230a7fc0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -914,23 +914,40 @@ namespace AZ { // make sure to only import the resource one time RHI::AttachmentId attachmentId = attachment->GetAttachmentId(); - if (!attachmentDatabase.IsAttachmentValid(attachmentId)) + const RHI::FrameAttachment* currentAttachment = attachmentDatabase.FindAttachment(attachmentId); + + if (azrtti_istypeof(attachment->m_importedResource.get())) { - if (azrtti_istypeof(attachment->m_importedResource.get())) + Image* image = static_cast(attachment->m_importedResource.get()); + if (currentAttachment == nullptr) { - Image* image = static_cast(attachment->m_importedResource.get()); attachmentDatabase.ImportImage(attachmentId, image->GetRHIImage()); } - else if (azrtti_istypeof(attachment->m_importedResource.get())) + else + { + AZ_Assert(currentAttachment->GetResource() == image->GetRHIImage(), + "Importing image attachment named \"%s\" but a different attachment with the " + "same name already exists in the database.\n", attachmentId.GetCStr()); + } + } + else if (azrtti_istypeof(attachment->m_importedResource.get())) + { + Buffer* buffer = static_cast(attachment->m_importedResource.get()); + if (currentAttachment == nullptr) { - Buffer* buffer = static_cast(attachment->m_importedResource.get()); attachmentDatabase.ImportBuffer(attachmentId, buffer->GetRHIBuffer()); } else { - AZ_RPI_PASS_ERROR(false, "Can't import unknown resource type"); + AZ_Assert(currentAttachment->GetResource() == buffer->GetRHIBuffer(), + "Importing buffer attachment named \"%s\" but a different attachment with the " + "same name already exists in the database.\n", attachmentId.GetCStr()); } } + else + { + AZ_RPI_PASS_ERROR(false, "Can't import unknown resource type"); + } } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp index a5082c5ee6..3bd26a5906 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassAttachment.cpp @@ -114,9 +114,9 @@ namespace AZ return RHI::TransientBufferDescriptor(GetAttachmentId(), m_descriptor.m_buffer); } - void PassAttachment::Update() + void PassAttachment::Update(bool updateImportedAttachments) { - if (m_descriptor.m_type == RHI::AttachmentType::Image && m_lifetime == RHI::AttachmentLifetimeType::Transient) + if (m_descriptor.m_type == RHI::AttachmentType::Image && (m_lifetime == RHI::AttachmentLifetimeType::Transient || updateImportedAttachments == true)) { if (m_settingFlags.m_getFormatFromPipeline && m_renderPipelineSource) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index bd0e15fb2e..24dfcb7097 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -127,7 +127,6 @@ namespace AZ m_worldToViewMatrix = worldToView; m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix; - m_worldToClipMatrixChanged = true; m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix); m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix); @@ -166,8 +165,6 @@ namespace AZ m_worldToViewMatrix = m_viewToWorldMatrix.GetInverseFast(); m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix; - m_clipToWorldMatrix = m_viewToWorldMatrix * m_clipToViewMatrix; - m_worldToClipMatrixChanged = true; m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix); m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix); @@ -178,12 +175,8 @@ namespace AZ void View::SetViewToClipMatrix(const AZ::Matrix4x4& viewToClip) { m_viewToClipMatrix = viewToClip; - m_clipToViewMatrix = viewToClip.GetInverseFull(); m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix; - m_worldToClipMatrixChanged = true; - - m_clipToWorldMatrix = m_viewToWorldMatrix * m_clipToViewMatrix; // Update z depth constant simultaneously // zNear -> n, zFar -> f @@ -210,6 +203,12 @@ namespace AZ InvalidateSrg(); } + + void View::SetClipSpaceOffset(float xOffset, float yOffset) + { + m_clipSpaceOffset.Set(xOffset, yOffset); + InvalidateSrg(); + } const AZ::Matrix4x4& View::GetWorldToViewMatrix() const { @@ -368,36 +367,56 @@ namespace AZ void View::UpdateSrg() { - if (m_worldToClipPrevMatrixNeedsUpdate) + if (m_needBuildSrg) { - m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, m_worldToClipPrevMatrix); - m_worldToClipPrevMatrixNeedsUpdate = false; + if (m_clipSpaceOffset.IsZero()) + { + Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix; + m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix); + m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix); + m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix); + m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix); + m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull()); + } + else + { + // Offset the current and previous frame clip matricies + Matrix4x4 offsetViewToClipMatrix = m_viewToClipMatrix; + offsetViewToClipMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX()); + offsetViewToClipMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY()); + + Matrix4x4 offsetViewToClipPrevMatrix = m_viewToClipPrevMatrix; + offsetViewToClipPrevMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX()); + offsetViewToClipPrevMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY()); + + // Build other matricies dependent on the view to clip matricies + Matrix4x4 offsetWorldToClipMatrix = offsetViewToClipMatrix * m_worldToViewMatrix; + Matrix4x4 offsetWorldToClipPrevMatrix = offsetViewToClipPrevMatrix * m_worldToViewPrevMatrix; + + Matrix4x4 offsetClipToViewMatrix = offsetViewToClipMatrix.GetInverseFull(); + Matrix4x4 offsetClipToWorldMatrix = m_viewToWorldMatrix * offsetClipToViewMatrix; + + m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix); + m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix); + m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix); + m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetClipToWorldMatrix); + m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull()); + } + + m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position); + m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix); + m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull()); + m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ); + m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants); + + m_shaderResourceGroup->Compile(); + m_needBuildSrg = false; } - if (m_worldToClipMatrixChanged) - { - m_worldToClipPrevMatrix = m_worldToClipMatrix; - m_worldToClipPrevMatrixNeedsUpdate = true; - m_worldToClipMatrixChanged = false; - } + m_viewToClipPrevMatrix = m_viewToClipMatrix; + m_worldToViewPrevMatrix = m_worldToViewMatrix; - if (!m_needBuildSrg) - { - return; - } - - m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position); - m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix); - m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix); - m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_worldToViewMatrix.GetInverseFull()); - m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix); - m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_viewToClipMatrix.GetInverseFull()); - m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_nearZ_farZ_farZTimesNearZ_farZMinusNearZ); - m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix); - m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants); - - m_shaderResourceGroup->Compile(); - m_needBuildSrg = false; + m_clipSpaceOffset.Set(0); } void View::BeginCulling() From 7984f82e481b2ddac0a8ebb7f2b28b4aa9d8f9d8 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Fri, 4 Jun 2021 23:03:17 -0400 Subject: [PATCH 129/153] Bing project_properties CLI to updateProject method. Update project info struct. Update project properties cli to support lists for tags. Minor adjustments to support changes. --- .../ProjectManager/Source/ProjectInfo.cpp | 7 ++- .../Tools/ProjectManager/Source/ProjectInfo.h | 13 ++++-- .../ProjectManager/Source/PythonBindings.cpp | 45 +++++++++++-------- .../ProjectManager/Source/PythonBindings.h | 7 +-- .../Source/PythonBindingsInterface.h | 21 +-------- .../Source/UpdateProjectCtrl.cpp | 6 +-- scripts/o3de/o3de/project_properties.py | 22 ++++----- 7 files changed, 59 insertions(+), 62 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index f0dc05cc62..f470841f09 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -15,14 +15,19 @@ namespace O3DE::ProjectManager { ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, - const QString& imagePath, const QString& backgroundImagePath, bool isNew) + const QString& origin, const QString& summary, const QString& imagePath, const QString& backgroundImagePath, + bool isNew) : m_path(path) , m_projectName(projectName) , m_displayName(displayName) + , m_origin(origin) + , m_summary(summary) , m_imagePath(imagePath) , m_backgroundImagePath(backgroundImagePath) , m_isNew(isNew) { + m_userTags = QStringList(); + m_userTagsForRemoval = QStringList(); } bool ProjectInfo::operator==(const ProjectInfo& rhs) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 71fa12b344..699d0997c6 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -15,6 +15,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #endif namespace O3DE::ProjectManager @@ -23,8 +24,8 @@ namespace O3DE::ProjectManager { public: ProjectInfo() = default; - ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, - const QString& imagePath, const QString& backgroundImagePath, bool isNew); + ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, const QString& origin, + const QString& summary, const QString& imagePath, const QString& backgroundImagePath, bool isNew); bool operator==(const ProjectInfo& rhs); bool operator!=(const ProjectInfo& rhs); @@ -36,12 +37,18 @@ namespace O3DE::ProjectManager // From project.json QString m_projectName; QString m_displayName; + QString m_origin; + QString m_summary; + QStringList m_userTags; // Used on projects home screen QString m_imagePath; - QString m_backgroundImagePath; + QStringList m_backgroundImagePath; // Used in project creation bool m_isNew = false; //! Is this a new project or existing + + // Used to flag tags for removal + QStringList m_userTagsForRemoval; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 0acbf8ffaf..16bcd6e122 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #pragma pop_macro("slots") #include @@ -687,23 +688,6 @@ namespace O3DE::ProjectManager return projectInfo; } - AZ::Outcome PythonBindings::ModifyProjectProperties(const QString& path, const QString& origin, const QString& displayName, - const QString& summary, const QString& icon, const QString& addTag, const QString& removeTag) - { - return ExecuteWithLockErrorHandling([&] - { - m_editProjectProperties.attr("edit_project_props")( - pybind11::str(path.toStdString()), //proj_path - pybind11::none(), //proj_name not used - origin.isNull() ? pybind11::none() : pybind11::str(origin.toStdString()), //new_origin - displayName.isNull() ? pybind11::none() : pybind11::str(displayName.toStdString()), //new_display - summary.isNull() ? pybind11::none() : pybind11::str(summary.toStdString()), //new_summary - icon.isNull() ? pybind11::none() : pybind11::str(icon.toStdString()), //new_icon - addTag.isNull() ? pybind11::none() : pybind11::str(addTag.toStdString()), //new_tag - removeTag.isNull() ? pybind11::none() : pybind11::str(removeTag.toStdString())); //remove_tag - }); - } - AZ::Outcome> PythonBindings::GetProjects() { QVector projects; @@ -764,9 +748,32 @@ namespace O3DE::ProjectManager }); } - bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) + AZ::Outcome PythonBindings::UpdateProject(const ProjectInfo& projectInfo) { - return false; + return ExecuteWithLockErrorHandling([&] + { + std::list newTags; + for (auto& i : projectInfo.m_userTags) + { + newTags.push_back(i.toStdString()); + } + + std::list removedTags; + for (auto& i : projectInfo.m_userTagsForRemoval) + { + removedTags.push_back(i.toStdString()); + } + + m_editProjectProperties.attr("edit_project_props")( + pybind11::str(projectInfo.m_path.toStdString()), // proj_path + pybind11::none(), // proj_name not used + pybind11::str(projectInfo.m_origin.toStdString()), // new_origin + pybind11::str(projectInfo.m_displayName.toStdString()), // new_display + pybind11::str(projectInfo.m_summary.toStdString()), // new_summary + pybind11::str(projectInfo.m_imagePath.toStdString()), // new_icon + pybind11::list(pybind11::cast(newTags)), // new_tag + pybind11::list(pybind11::cast(removedTags))); // remove_tag + }); } ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 5f03d0ab28..707595b6fd 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -50,14 +50,9 @@ namespace O3DE::ProjectManager AZ::Outcome> GetProjects() override; bool AddProject(const QString& path) override; bool RemoveProject(const QString& path) override; - bool UpdateProject(const ProjectInfo& projectInfo) override; + AZ::Outcome UpdateProject(const ProjectInfo& projectInfo) override; AZ::Outcome AddGemToProject(const QString& gemPath, const QString& projectPath) override; AZ::Outcome RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override; - AZ::Outcome ModifyProjectProperties( - const QString& path, - const QString& origin = 0, - const QString& displayName = 0, - const QString& summary = 0, const QString& icon = 0, const QString& addTag = 0, const QString& removeTag = 0) override; // ProjectTemplate AZ::Outcome> GetProjectTemplates() override; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index edc9510236..fd94a4e964 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -122,7 +122,7 @@ namespace O3DE::ProjectManager * @param projectInfo the info to use to update the project * @return true on success, false on failure */ - virtual bool UpdateProject(const ProjectInfo& projectInfo) = 0; + virtual AZ::Outcome UpdateProject(const ProjectInfo& projectInfo) = 0; /** * Add a gem to a project @@ -132,25 +132,6 @@ namespace O3DE::ProjectManager */ virtual AZ::Outcome AddGemToProject(const QString& gemPath, const QString& projectPath) = 0; - /** - * Change property in project json file - * @param path the absolute path to the gem - * @param origin the description or url for project origin (such as project host, repository, owner...etc) - * @param displayName the project display name - * @param summary short description of the project - * @param icon image used to represent the project - * @param addTag user tag to be added - * @param removeTag user tag to be removed - */ - virtual AZ::Outcome ModifyProjectProperties( - const QString& path, - const QString& origin = 0, - const QString& displayName = 0, - const QString& summary = 0, - const QString& icon = 0, - const QString& addTag = 0, - const QString& removeTag = 0) = 0; - /** * Remove gem to a project * @param gemPath the absolute path to the gem diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index a383a0f93b..19078f65ea 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -134,10 +134,10 @@ namespace O3DE::ProjectManager // Update project if settings changed if (m_projectInfo != newProjectSettings) { - bool result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings); - if (!result) + auto result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings); + if (!result.IsSuccess()) { - QMessageBox::critical(this, tr("Project update failed"), tr("Failed to update project.")); + QMessageBox::critical(this, tr("Project update failed"), tr(result.GetError().c_str())); return; } } diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 69bd1b9406..83e76fc18f 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -45,15 +45,17 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display, if new_icon: proj_json['icon_path'] = new_icon if new_tag: - proj_json.setdefault('user_tags', []).append(new_tag) + for tag in new_tag: + proj_json.setdefault('user_tags', []).append(tag) if remove_tag: if 'user_tags' in proj_json: - if remove_tag in proj_json['user_tags']: - proj_json['user_tags'].remove(remove_tag) - else: - logger.warn(f'{remove_tag} not found in user_tags for removal.') + for del_tag in remove_tag: + if del_tag in proj_json['user_tags']: + proj_json['user_tags'].remove(del_tag) + else: + logger.warn(f'{del_tag} not found in user_tags for removal.') else: - logger.warn(f'user_tags property not found for removal of tag {remove_tag}.') + logger.warn(f'user_tags property not found for removal of {remove_tag}.') manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json') return 0 @@ -83,10 +85,10 @@ def add_parser_args(parser): help='Sets the summary description of the project.') group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') - group.add_argument('-pt', '--project-tag', type=str, required=False, - help='Adds a tag to user_tags property. These tags are intended for documentation and filtering.') - group.add_argument('-rt', '--remove-tag', type=str, required=False, - help='Removes a tag from the user_tags property.') + group.add_argument('-pt', '--project-tag', type=default, required=False, + help='Adds tag(s) to user_tags property. These tags are intended for documentation and filtering.') + group.add_argument('-rt', '--remove-tag', type=default, required=False, + help='Removes tag(s) from the user_tags property.') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: From 155271a0ee164610e70cb93726f14b67103859e8 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Fri, 4 Jun 2021 23:07:36 -0400 Subject: [PATCH 130/153] Fixed data type changed by mistake for project info image path --- Code/Tools/ProjectManager/Source/ProjectInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 699d0997c6..63f509af18 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -43,7 +43,7 @@ namespace O3DE::ProjectManager // Used on projects home screen QString m_imagePath; - QStringList m_backgroundImagePath; + QString m_backgroundImagePath; // Used in project creation bool m_isNew = false; //! Is this a new project or existing From d2f8e4903719dfb97ec08795432106ce45ebbf13 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Fri, 4 Jun 2021 23:16:25 -0400 Subject: [PATCH 131/153] resolving merge conflict due to variable name change from main --- Code/Tools/ProjectManager/Source/ProjectInfo.cpp | 4 ++-- Code/Tools/ProjectManager/Source/ProjectInfo.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index f470841f09..85716fccfa 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -16,7 +16,7 @@ namespace O3DE::ProjectManager { ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, const QString& origin, const QString& summary, const QString& imagePath, const QString& backgroundImagePath, - bool isNew) + bool needsBuild) : m_path(path) , m_projectName(projectName) , m_displayName(displayName) @@ -24,7 +24,7 @@ namespace O3DE::ProjectManager , m_summary(summary) , m_imagePath(imagePath) , m_backgroundImagePath(backgroundImagePath) - , m_isNew(isNew) + , m_needsBuild(needsBuild) { m_userTags = QStringList(); m_userTagsForRemoval = QStringList(); diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 63f509af18..99ab8ebf31 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager public: ProjectInfo() = default; ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, const QString& origin, - const QString& summary, const QString& imagePath, const QString& backgroundImagePath, bool isNew); + const QString& summary, const QString& imagePath, const QString& backgroundImagePath, bool needsBuild); bool operator==(const ProjectInfo& rhs); bool operator!=(const ProjectInfo& rhs); @@ -46,7 +46,7 @@ namespace O3DE::ProjectManager QString m_backgroundImagePath; // Used in project creation - bool m_isNew = false; //! Is this a new project or existing + bool m_needsBuild = false; //! Is this a new project or existing // Used to flag tags for removal QStringList m_userTagsForRemoval; From 0334aa1b1c1f4fc13495537e7b272263a16ef772 Mon Sep 17 00:00:00 2001 From: Peng Date: Fri, 4 Jun 2021 20:17:32 -0700 Subject: [PATCH 132/153] ATOM-15723 [RHI][Vulkan] Set unbounded array support based on physical device indexing features JIRA: https://jira.agscollab.com/browse/ATOM-15723 --- Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp index 76662ebc6e..04f2465e78 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp @@ -720,7 +720,7 @@ namespace AZ StringList deviceExtensions = physicalDevice.GetDeviceExtensionNames(); StringList::iterator itRayTracingExtension = AZStd::find(deviceExtensions.begin(), deviceExtensions.end(), VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); m_features.m_rayTracing = (itRayTracingExtension != deviceExtensions.end()); - m_features.m_unboundedArrays = true; + m_features.m_unboundedArrays = physicalDevice.GetPhysicalDeviceDescriptorIndexingFeatures().shaderStorageTexelBufferArrayNonUniformIndexing; const auto& deviceLimits = physicalDevice.GetDeviceLimits(); m_limits.m_maxImageDimension1D = deviceLimits.maxImageDimension1D; From bf29b27937f4f1ff0828a6b49859e7e0570b685e Mon Sep 17 00:00:00 2001 From: amzn-hdoke <61443753+hdoke@users.noreply.github.com> Date: Fri, 4 Jun 2021 20:48:35 -0700 Subject: [PATCH 133/153] Add AWSAttribution feature (#1164) * LYN-3601: Provide skeleton classes for AWS Attribution (#31) Provide skeleton classes for AWS Attribution, along with some basic unit tests * Add AWS Attribution UI and settings (#56) * Adding AWS Attributions UX and corresponding editor preference s setting * Fix serialized field description * Fixed update frequency to be a day * Handling editor startup with default values for AWSAttribution * Add missing header and remove AWSCoreSystemComponentMock fron test * Generate and post AWSAttribution metric (#69) * Adding AWS Attribution Api service job * Adding support for config endpoint override * Update Api endpoint formatting, fix default region * Remove extra header * Fixes for link issues * Fix Unittest namespace * Instantiating AWSAttributionSystemComponent in AWS.Editor module * Update AttributionMetric with engine version and AWS enabled gems (#77) * Update AttributionMetric with engine version and AWS enabled gems * Fix warnings * Undoing accidental change * Saving level PrefabLevel_OpensLevelWithEntities * Remove overriding editorprefrences.setreg * Revert "Saving level PrefabLevel_OpensLevelWithEntities" This reverts commit 529af70c55ece70fc6bc29ceb83bef60413713a3. * Move AWS preferences to its own temp settings file * Undo accidental file add * Add missing string params in warning messages Co-authored-by: Pip Potter <61438964+lmbr-pip@users.noreply.github.com> --- .../Editor/EditorPreferencesDialog.cpp | 2 + .../Editor/EditorPreferencesPageAWS.cpp | 151 +++++++ .../Sandbox/Editor/EditorPreferencesPageAWS.h | 60 +++ Code/Sandbox/Editor/MainWindow.qrc | 1 + Code/Sandbox/Editor/PreferencesStdPages.cpp | 8 + Code/Sandbox/Editor/editor_lib_files.cmake | 2 + .../Editor/res/AWS_preferences_icon.svg | 3 + Gems/AWSCore/Code/CMakeLists.txt | 4 +- .../Include/Private/AWSCoreEditorModule.h | 2 +- .../Attribution/AWSAttributionServiceApi.h | 71 +++ .../Attribution/AWSCoreAttributionConstant.h | 25 ++ .../Attribution/AWSCoreAttributionManager.h | 53 +++ .../Attribution/AWSCoreAttributionMetric.h | 62 +++ .../AWSCoreAttributionSystemComponent.h | 50 +++ .../Public/Framework/ServiceClientJobConfig.h | 6 + .../Code/Source/AWSCoreEditorModule.cpp | 5 +- .../Attribution/AWSAttributionServiceApi.cpp | 45 ++ .../Attribution/AWSCoreAttributionManager.cpp | 275 ++++++++++++ .../Attribution/AWSCoreAttributionMetric.cpp | 106 +++++ .../AWSCoreAttributionSystemComponent.cpp | 81 ++++ .../AWSAttributionServiceApiTest.cpp | 85 ++++ .../AWSCoreAttributionManagerTest.cpp | 414 ++++++++++++++++++ .../AWSCoreAttributionMetricTest.cpp | 50 +++ .../AWSCoreAttributionSystemComponentTest.cpp | 132 ++++++ .../Code/Tests/TestFramework/AWSCoreFixture.h | 31 +- Gems/AWSCore/Code/awscore_editor_files.cmake | 9 + .../Code/awscore_editor_tests_files.cmake | 4 + 27 files changed, 1732 insertions(+), 5 deletions(-) create mode 100644 Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp create mode 100644 Code/Sandbox/Editor/EditorPreferencesPageAWS.h create mode 100644 Code/Sandbox/Editor/res/AWS_preferences_icon.svg create mode 100644 Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h create mode 100644 Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h create mode 100644 Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionManager.h create mode 100644 Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h create mode 100644 Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h create mode 100644 Gems/AWSCore/Code/Source/Editor/Attribution/AWSAttributionServiceApi.cpp create mode 100644 Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp create mode 100644 Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp create mode 100644 Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp create mode 100644 Gems/AWSCore/Code/Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp create mode 100644 Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp create mode 100644 Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp create mode 100644 Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp diff --git a/Code/Sandbox/Editor/EditorPreferencesDialog.cpp b/Code/Sandbox/Editor/EditorPreferencesDialog.cpp index e5bcfd6bad..679c73e7df 100644 --- a/Code/Sandbox/Editor/EditorPreferencesDialog.cpp +++ b/Code/Sandbox/Editor/EditorPreferencesDialog.cpp @@ -35,6 +35,7 @@ #include "EditorPreferencesPageViewportMovement.h" #include "EditorPreferencesPageViewportDebug.h" #include "EditorPreferencesPageExperimentalLighting.h" +#include "EditorPreferencesPageAWS.h" #include "LyViewPaneNames.h" AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING @@ -72,6 +73,7 @@ EditorPreferencesDialog::EditorPreferencesDialog(QWidget* pParent) CEditorPreferencesPage_ViewportMovement::Reflect(*serializeContext); CEditorPreferencesPage_ViewportDebug::Reflect(*serializeContext); CEditorPreferencesPage_ExperimentalLighting::Reflect(*serializeContext); + CEditorPreferencesPage_AWS::Reflect(*serializeContext); } } diff --git a/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp b/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp new file mode 100644 index 0000000000..edaf813cd8 --- /dev/null +++ b/Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp @@ -0,0 +1,151 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#include "EditorDefs.h" + +#include "EditorPreferencesPageAWS.h" + +// AzCore +#include +#include +#include + +void CEditorPreferencesPage_AWS::Reflect(AZ::SerializeContext& serialize) +{ + serialize.Class() + ->Version(1) + ->Field("AWSAttributionEnabled", &UsageOptions::m_awsAttributionEnabled); + + serialize.Class() + ->Version(1) + ->Field("UsageOptions", &CEditorPreferencesPage_AWS::m_usageOptions); + + AZ::EditContext* editContext = serialize.GetEditContext(); + if (editContext) + { + editContext->Class("Options", "") + ->DataElement(AZ::Edit::UIHandlers::CheckBox, &UsageOptions::m_awsAttributionEnabled, "Send Metrics usage to AWS", + "Reports Gem usage to AWS on Editor launch"); + + editContext->Class("AWS Preferences", "AWS Preferences") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20)) + ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_AWS::m_usageOptions, "AWS Usage Data", "AWS Usage Options"); + } +} + + +CEditorPreferencesPage_AWS::CEditorPreferencesPage_AWS() +{ + m_settingsRegistry = AZStd::make_unique(); + InitializeSettings(); + + // TODO Update with AWS svg. + m_icon = QIcon(":/res/AWS_preferences_icon.svg"); +} + +CEditorPreferencesPage_AWS::~CEditorPreferencesPage_AWS() +{ + m_settingsRegistry.reset(); +} + +const char* CEditorPreferencesPage_AWS::GetTitle() +{ + return "AWS"; +} + +QIcon& CEditorPreferencesPage_AWS::GetIcon() +{ + return m_icon; +} + +void CEditorPreferencesPage_AWS::OnApply() +{ + m_settingsRegistry->Set(AWSAttributionEnabledKey, m_usageOptions.m_awsAttributionEnabled); + SaveSettingsRegistryFile(); +} + +const CEditorPreferencesPage_AWS::UsageOptions& CEditorPreferencesPage_AWS::GetUsageOptions() +{ + return m_usageOptions; +} + +void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile() +{ + AZ::Job* job = AZ::CreateJobFunction( + [this]() + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + + // Resolve path to editor_aws_preferences.setreg + AZStd::string editorPreferencesFilePath = + AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); + AZStd::array resolvedPath{}; + fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size()); + + AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; + dumperSettings.m_prettifyOutput = true; + dumperSettings.m_jsonPointerPrefix = AWSAttributionSettingsPrefixKey; + + AZStd::string stringBuffer; + AZ::IO::ByteContainerStream stringStream(&stringBuffer); + if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream( + *m_settingsRegistry, AWSAttributionSettingsPrefixKey, stringStream, dumperSettings)) + { + AZ_Warning( + "AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)", + resolvedPath.data()); + return; + } + + bool saved{}; + constexpr auto configurationMode = + AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; + if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode)) + { + saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size(); + } + + AZ_Warning( + "AWSAttributionManager", saved, R"(Unable to save Editor AWS Preferences registry file to path "%s"\n)", + editorPreferencesFilePath.c_str()); + }, + true); + job->Start(); +} + +void CEditorPreferencesPage_AWS::InitializeSettings() +{ + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + + // Resolve path to editor_aws_preferences.setreg + AZStd::string editorAWSPreferencesFilePath = + AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); + AZStd::array resolvedPathAWSPreference{}; + if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size())) + { + AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data()); + return; + } + + if (fileIO->Exists(resolvedPathAWSPreference.data())) + { + m_settingsRegistry->MergeSettingsFile(resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + } + + if (!m_settingsRegistry->Get(m_usageOptions.m_awsAttributionEnabled, AWSAttributionEnabledKey)) + { + // If key is missing default to on. + m_usageOptions.m_awsAttributionEnabled = true; + } +} diff --git a/Code/Sandbox/Editor/EditorPreferencesPageAWS.h b/Code/Sandbox/Editor/EditorPreferencesPageAWS.h new file mode 100644 index 0000000000..b0dc7ee740 --- /dev/null +++ b/Code/Sandbox/Editor/EditorPreferencesPageAWS.h @@ -0,0 +1,60 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include "Include/IPreferencesPage.h" +#include +#include +#include +#include + +class CEditorPreferencesPage_AWS + : public IPreferencesPage +{ +public: + AZ_RTTI(CEditorPreferencesPage_AWS, "{51FB9557-ABA3-4FD7-803A-1784F5B06F5F}", IPreferencesPage) + + static void Reflect(AZ::SerializeContext& serialize); + + CEditorPreferencesPage_AWS(); + virtual ~CEditorPreferencesPage_AWS(); + + // IPreferencesPage interface methods. + virtual const char* GetCategory() override { return "AWS"; } + virtual const char* GetTitle() override; + virtual QIcon& GetIcon() override; + virtual void OnApply() override; + virtual void OnCancel() override {} + virtual bool OnQueryCancel() override { return true; } + +protected: + struct UsageOptions + { + AZ_TYPE_INFO(UsageOptions, "{2B7D9B19-D13B-4E54-B724-B2FD8D0828B3}") + + bool m_awsAttributionEnabled; + }; + + const UsageOptions& GetUsageOptions(); + +private: + void InitializeSettings(); + void SaveSettingsRegistryFile(); + UsageOptions m_usageOptions; + QIcon m_icon; + AZStd::unique_ptr m_settingsRegistry; + + static constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled"; + static constexpr char EditorPreferencesFileName[] = "editorpreferences.setreg"; + static constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg"; + static constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences"; +}; diff --git a/Code/Sandbox/Editor/MainWindow.qrc b/Code/Sandbox/Editor/MainWindow.qrc index 476159fbfd..fd207ebe13 100644 --- a/Code/Sandbox/Editor/MainWindow.qrc +++ b/Code/Sandbox/Editor/MainWindow.qrc @@ -143,6 +143,7 @@ res/Camera.svg res/Debug.svg res/Experimental.svg + res/AWS_preferences_icon.svg res/Files.svg res/Gizmos.svg res/Global.svg diff --git a/Code/Sandbox/Editor/PreferencesStdPages.cpp b/Code/Sandbox/Editor/PreferencesStdPages.cpp index 032b01e353..3a66d6e3f4 100644 --- a/Code/Sandbox/Editor/PreferencesStdPages.cpp +++ b/Code/Sandbox/Editor/PreferencesStdPages.cpp @@ -15,6 +15,8 @@ #include "PreferencesStdPages.h" +#include + // Editor #include "EditorPreferencesPageGeneral.h" #include "EditorPreferencesPageFiles.h" @@ -23,6 +25,7 @@ #include "EditorPreferencesPageViewportMovement.h" #include "EditorPreferencesPageViewportDebug.h" #include "EditorPreferencesPageExperimentalLighting.h" +#include "EditorPreferencesPageAWS.h" ////////////////////////////////////////////////////////////////////////// @@ -42,6 +45,11 @@ CStdPreferencesClassDesc::CStdPreferencesClassDesc() }; m_pageCreators.push_back([]() { return new CEditorPreferencesPage_ExperimentalLighting(); }); + + if (AzToolsFramework::IsComponentWithServiceRegistered(AZ_CRC_CE("AWSCoreEditorService"))) + { + m_pageCreators.push_back([]() { return new CEditorPreferencesPage_AWS(); }); + } } HRESULT CStdPreferencesClassDesc::QueryInterface(const IID& riid, void** ppvObj) diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index e1cf18df55..ebd7f89cfb 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -586,6 +586,8 @@ set(FILES EditorPreferencesPageViewportDebug.cpp EditorPreferencesPageExperimentalLighting.h EditorPreferencesPageExperimentalLighting.cpp + EditorPreferencesPageAWS.h + EditorPreferencesPageAWS.cpp EditorPreferencesDialog.h EditorPreferencesDialog.cpp EditorPreferencesDialog.ui diff --git a/Code/Sandbox/Editor/res/AWS_preferences_icon.svg b/Code/Sandbox/Editor/res/AWS_preferences_icon.svg new file mode 100644 index 0000000000..e2a86cf162 --- /dev/null +++ b/Code/Sandbox/Editor/res/AWS_preferences_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index 7edb22124f..d6cd57355f 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -64,11 +64,13 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Include/Public BUILD_DEPENDENCIES PRIVATE + AZ::AzQtComponents 3rdParty::Qt::Core 3rdParty::Qt::Widgets - AZ::AzQtComponents + Gem::AWSCore.Static PUBLIC AZ::AzToolsFramework + 3rdParty::AWSNativeSDK::AWSCore ) ly_add_target( diff --git a/Gems/AWSCore/Code/Include/Private/AWSCoreEditorModule.h b/Gems/AWSCore/Code/Include/Private/AWSCoreEditorModule.h index 45a2c1f9f7..144976f355 100644 --- a/Gems/AWSCore/Code/Include/Private/AWSCoreEditorModule.h +++ b/Gems/AWSCore/Code/Include/Private/AWSCoreEditorModule.h @@ -16,7 +16,7 @@ namespace AWSCore { class AWSCoreEditorModule - :public AZ::Module + : public AZ::Module { public: AZ_RTTI(AWSCoreEditorModule, "{C1C9B898-848B-4C2F-A7AA-69642D12BCB5}", AZ::Module); diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h new file mode 100644 index 0000000000..d14e51589c --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h @@ -0,0 +1,71 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AWSCore +{ + namespace ServiceAPI + { + //! Struct for storing the success response. + struct AWSAtrributionSuccessResponse + { + //! Identify the expected property type and provide a location where the property value can be stored. + //! @param key Name of the property. + //! @param reader JSON reader to read the property. + bool OnJsonKey(const char* key, AWSCore::JsonReader& reader); + + AZStd::string result; //!< Processing result for the input record. + }; + + // Service RequestJobs + AWS_FEATURE_GEM_SERVICE(AWSAttribution); + + //! POST request to send attribution metric to the backend. + //! The path for this service API is "/prod/metrics". + class AWSAttributionRequest + : public AWSCore::ServiceRequest + { + public: + SERVICE_REQUEST(AWSAttribution, HttpMethod::HTTP_POST, "/metrics"); + + bool UseAWSCredentials() + { + return false; + } + + //! Request body for the service API request. + struct Parameters + { + //! Build the service API request. + //! @request Builder for generating the request. + //! @return Whether the request is built successfully. + bool BuildRequest(AWSCore::RequestBuilder& request); + + //! Write to the service API request body. + //! @param writer JSON writer for the serialization. + //! @return Whether the serialization is successful. + bool WriteJson(AWSCore::JsonWriter& writer) const; + + AttributionMetric metric; + }; + + AWSAtrributionSuccessResponse result; + Parameters parameters; //! Request parameter. + }; + + using AWSAttributionRequestJob = AWSCore::ServiceRequestJob; + } // ServiceAPI +} // AWSMetrics diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h new file mode 100644 index 0000000000..503abfb9cf --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h @@ -0,0 +1,25 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +namespace AWSCore +{ + //! Default metrics attribute keys + static constexpr char AwsAttributionAttributeKeyVersion[] = "version"; + static constexpr char AwsAttributionAttributeKeyO3DEVersion[] = "o3de_version"; + static constexpr char AwsAttributionAttributeKeyPlatform[] = "platform"; + static constexpr char AwsAttributionAttributeKeyPlatformVersion[] = "platform_version"; + static constexpr char AwsAttributionAttributeKeyActiveAWSGems[] = "aws_gems"; + static constexpr char AwsAttributionAttributeKeyTimestamp[] = "timestamp"; + +} // namespace AWSCOre diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionManager.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionManager.h new file mode 100644 index 0000000000..ad3b8c72c9 --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionManager.h @@ -0,0 +1,53 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once +#include +#include + +#include +#include + +namespace AWSCore +{ + //! Manages operational metrics for AWS gems + class AWSAttributionManager + { + public: + AWSAttributionManager(); + virtual ~AWSAttributionManager(); + + //! Perform initialization + void Init(); + + //! Run metric check + void MetricCheck(); + + protected: + virtual void SubmitMetric(AttributionMetric& metric); + virtual void UpdateMetric(AttributionMetric& metric); + void UpdateLastSend(); + void SetApiEndpointAndRegion(ServiceAPI::AWSAttributionRequestJob::Config* config); + + private: + bool ShouldGenerateMetric() const; + + AZStd::string GetEngineVersion() const; + AZStd::string GetPlatform() const; + void GetActiveAWSGems(AZStd::vector& gemNames); + + void SaveSettingsRegistryFile(); + + AZStd::unique_ptr m_settingsRegistry; + }; + +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h new file mode 100644 index 0000000000..42518b8df5 --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h @@ -0,0 +1,62 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or + * a third party where indicated. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace AWSCore +{ + //! Defines the operational metric sent periodically + class AttributionMetric + { + public: + AZ_TYPE_INFO(MetricsAttribute, "{6483F481-0C18-4171-8B59-A44F2F28EAE5}") + + AttributionMetric(); + AttributionMetric(const AZStd::string& timestamp); + ~AttributionMetric() = default; + + void SetO3DEVersion(const AZStd::string& version); + void SetPlatform(const AZStd::string& platform, const AZStd::string& platformVersion); + void AddActiveGem(const AZStd::string& gemName); + + //! Serialize the metrics object queue to a string. + //! @return Serialized string. + AZStd::string SerializeToJson(); + + //! Serialize the metrics object to JSON for the sending requests. + //! @param writer JSON writer for the serialization. + //! @return Whether the metrics event is serialized successfully. + bool SerializeToJson(AWSCore::JsonWriter& writer) const; + + //! Read from a JSON value to the metrics event. + //! @param metricsObjVal JSON value to read from. + //! @return Whether the metrics event is created successfully. + bool ReadFromJson(rapidjson::Value& metricsObjVal); + + //! Generates a UTC 8601 formatted timestamp + static AZStd::string GenerateTimeStamp(); + private: + AZStd::string m_version; //!< Schema version in use + AZStd::string m_o3deVersion; //!< O3DE editor version in use + AZStd::string m_platform; //!< OS type + AZStd::string m_platformVersion; //!< OS subtype + AZStd::string m_timestamp; //!< Metric generation time + AZStd::vector m_activeAWSGems; //!< Active AWS Gems in project + }; +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h new file mode 100644 index 0000000000..476b7ba842 --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h @@ -0,0 +1,50 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include +#include + +namespace AWSCore +{ + class AWSAttributionManager; + + //! Attribution System Component. Responsible for instantiating and managing AWS Attribution Manager + class AWSAttributionSystemComponent: + public AZ::Component + { + public: + AZ_COMPONENT(AWSAttributionSystemComponent, "{366861EC-8337-4180-A202-4E4DF082A3A8}"); + + AWSAttributionSystemComponent(); + ~AWSAttributionSystemComponent() = default; + + static void Reflect(AZ::ReflectContext* context);\ + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + protected: + //////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Init() override; + void Activate() override; + void Deactivate() override; + //////////////////////////////////////////////////////////////////////// + + private: + AZStd::unique_ptr m_manager; //!< pointer to the attribution manager which handles operational metrics + }; +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h b/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h index 722fc098a0..709e786adc 100644 --- a/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h +++ b/Gems/AWSCore/Code/Include/Public/Framework/ServiceClientJobConfig.h @@ -113,7 +113,13 @@ namespace AWSCore /// needed. See it's use in ServiceRequestJobConfig. const AZStd::string GetServiceUrl() override { + if (endpointOverride.has_value()) + { + return endpointOverride.value().c_str(); + } + AZStd::string serviceUrl; + if (!ServiceTraitsType::RESTApiIdKeyName && !ServiceTraitsType::RESTApiStageKeyName) { AWSResourceMappingRequestBus::BroadcastResult( diff --git a/Gems/AWSCore/Code/Source/AWSCoreEditorModule.cpp b/Gems/AWSCore/Code/Source/AWSCoreEditorModule.cpp index 69e45bfd68..2f4519c960 100644 --- a/Gems/AWSCore/Code/Source/AWSCoreEditorModule.cpp +++ b/Gems/AWSCore/Code/Source/AWSCoreEditorModule.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace AWSCore { @@ -19,6 +20,7 @@ namespace AWSCore // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. m_descriptors.insert(m_descriptors.end(), { AWSCoreEditorSystemComponent::CreateDescriptor(), + AWSAttributionSystemComponent::CreateDescriptor() }); } @@ -28,7 +30,8 @@ namespace AWSCore AZ::ComponentTypeList AWSCoreEditorModule::GetRequiredSystemComponents() const { return AZ::ComponentTypeList{ - azrtti_typeid() + azrtti_typeid(), + azrtti_typeid() }; } diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSAttributionServiceApi.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSAttributionServiceApi.cpp new file mode 100644 index 0000000000..3c82ec98f9 --- /dev/null +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSAttributionServiceApi.cpp @@ -0,0 +1,45 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +namespace AWSCore +{ + namespace ServiceAPI + { + constexpr char AwsAttributionServiceResultResponseKey[] = "statusCode"; + + bool AWSAtrributionSuccessResponse::OnJsonKey(const char* key, AWSCore::JsonReader& reader) + { + if (strcmp(key, AwsAttributionServiceResultResponseKey) == 0) + { + return reader.Accept(result); + } + return reader.Ignore(); + } + + bool AWSAttributionRequest::Parameters::BuildRequest(AWSCore::RequestBuilder& request) + { + bool ok = true; + ok = ok && request.WriteJsonBodyParameter(*this); + return ok; + } + + bool AWSAttributionRequest::Parameters::WriteJson(AWSCore::JsonWriter& writer) const + { + bool ok = true; + ok = ok && metric.SerializeToJson(writer); + return ok; + } + } +} diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp new file mode 100644 index 0000000000..e7a6828903 --- /dev/null +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp @@ -0,0 +1,275 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace AWSCore +{ + static constexpr const char* EngineVersionJsonKey = "O3DEVersion"; + + constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg"; + constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences"; + constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled"; + constexpr char AWSAttributionDelaySecondsKey[] = "/Amazon/AWS/Preferences/AWSAttributionDelaySeconds"; + constexpr char AWSAttributionLastTimeStampKey[] = "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"; + constexpr char AWSAttributionApiId[] = "xbzx78kvbk"; + constexpr char AWSAttributionChinaApiId[] = ""; + constexpr char AWSAttributionApiStage[] = "prod"; + + AWSAttributionManager::AWSAttributionManager() + { + m_settingsRegistry = AZStd::make_unique(); + } + + AWSAttributionManager::~AWSAttributionManager() + { + m_settingsRegistry.reset(); + } + + void AWSAttributionManager::Init() + { + } + + void AWSAttributionManager::MetricCheck() + { + if (ShouldGenerateMetric()) + { + // 1. Gather metadata and assemble metric + AttributionMetric metric; + UpdateMetric(metric); + // 2. Identify region and chose attribution endpoint + + // 3. Post metric + SubmitMetric(metric); + } + } + + bool AWSAttributionManager::ShouldGenerateMetric() const + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + + // Resolve path to editor_aws_preferences.setreg + AZStd::string editorAWSPreferencesFilePath = + AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); + AZStd::array resolvedPathAWSPreference{}; + if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size())) + { + AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data()); + return false; + } + + if (fileIO->Exists(resolvedPathAWSPreference.data())) + { + m_settingsRegistry->MergeSettingsFile(resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + } + + bool awsAttributionEnabled = false; + if (!m_settingsRegistry->Get(awsAttributionEnabled, AWSAttributionEnabledKey)) + { + // If not found default to sending the metric. + awsAttributionEnabled = true; + } + + if (!awsAttributionEnabled) + { + return false; + } + + // If delayInSeconds is not found, set default to a day + AZ::u64 delayInSeconds = 0; + if (!m_settingsRegistry->Get(delayInSeconds, AWSAttributionDelaySecondsKey)) + { + AZ_Warning("AWSAttributionManager", false, "AWSAttribution delay key not found. Defaulting to delay to day"); + delayInSeconds = 86400; + m_settingsRegistry->Set(AWSAttributionDelaySecondsKey, delayInSeconds); + } + + AZ::u64 lastSendTimeStampSeconds = 0; + if (!m_settingsRegistry->Get(lastSendTimeStampSeconds, AWSAttributionLastTimeStampKey)) + { + // If last time stamp not found, assume this is the first attempt at sending. + return true; + } + + AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds); + AZStd::chrono::seconds secondsSinceLastSend = + AZStd::chrono::duration_cast(AZStd::chrono::system_clock::now().time_since_epoch()) - lastSendTimeStamp; + if (secondsSinceLastSend.count() >= delayInSeconds) + { + return true; + } + + return false; + } + + void AWSAttributionManager::SaveSettingsRegistryFile() + { + AZ::Job* job = AZ::CreateJobFunction( + [this]() + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + + // Resolve path to editor_aws_preferences.setreg + AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName); + AZStd::array resolvedPath {}; + fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size()); + + AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; + dumperSettings.m_prettifyOutput = true; + dumperSettings.m_jsonPointerPrefix = AWSAttributionSettingsPrefixKey; + + AZStd::string stringBuffer; + AZ::IO::ByteContainerStream stringStream(&stringBuffer); + if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream( + *m_settingsRegistry, AWSAttributionSettingsPrefixKey, stringStream, dumperSettings)) + { + AZ_Warning( + "AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)", + resolvedPath.data()); + return; + } + + bool saved {}; + constexpr auto configurationMode = + AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; + if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode)) + { + saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size(); + } + + AZ_Warning( + "AWSAttributionManager", saved, R"(Unable to save Editor AWS Preferences registry file to path "%s"\n)", + editorPreferencesFilePath.c_str()); + }, + true); + job->Start(); + + } + + void AWSAttributionManager::UpdateLastSend() + { + if (!m_settingsRegistry->Set(AWSAttributionLastTimeStampKey, + AZStd::chrono::duration_cast(AZStd::chrono::system_clock::now().time_since_epoch()).count())) + { + AZ_Warning("AWSAttributionManager", true, "Failed to set AWSAttributionLastTimeStamp"); + return; + } + SaveSettingsRegistryFile(); + } + + void AWSAttributionManager::SetApiEndpointAndRegion(AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config) + { + // Get default config for the process to check the region. + // Assumption to determine China region is the default profile is set to China region. + auto profile_name = Aws::Auth::GetConfigProfileName(); + Aws::Client::ClientConfiguration clientConfig(profile_name.c_str()); + AZStd::string apiId = AWSAttributionApiId; + + if (clientConfig.region == Aws::Region::CN_NORTH_1 || clientConfig.region == Aws::Region::CN_NORTHWEST_1) + { + config->region = Aws::Region::CN_NORTH_1; + apiId = AWSAttributionChinaApiId; + } + + config->region = Aws::Region::US_WEST_2; + config->endpointOverride = + AWSResourceMappingUtils::FormatRESTApiUrl(apiId, config->region.value().c_str(), AWSAttributionApiStage).c_str(); + } + + AZStd::string AWSAttributionManager::GetEngineVersion() const + { + AZStd::string engineVersion; + auto engineSettingsPath = AZ::IO::FixedMaxPath{ AZ::Utils::GetEnginePath() } / "engine.json"; + if (AZ::IO::SystemFile::Exists(engineSettingsPath.c_str())) + { + AZ::SettingsRegistryImpl settingsRegistry; + if (settingsRegistry.MergeSettingsFile( + engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey)) + { + settingsRegistry.Get(engineVersion, AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey) + "/" + EngineVersionJsonKey); + } + } + return engineVersion; + } + + AZStd::string AWSAttributionManager::GetPlatform() const + { + return AZ::GetPlatformName(AZ::g_currentPlatform); + } + + void AWSAttributionManager::GetActiveAWSGems(AZStd::vector& gems) + { + AZ::ModuleManagerRequestBus::Broadcast( + &AZ::ModuleManagerRequestBus::Events::EnumerateModules, + [this, &gems](const AZ::ModuleData& moduleData) + { + AZ::Entity* moduleEntity = moduleData.GetEntity(); + auto moduleEntityName = moduleEntity->GetName(); + if (moduleEntityName.contains("AWS")) + gems.push_back(moduleEntityName.substr(0, moduleEntityName.find_last_of("."))); + return true; + }); + } + + void AWSAttributionManager::UpdateMetric(AttributionMetric& metric) + { + AZStd::string engineVersion = this->GetEngineVersion(); + metric.SetO3DEVersion(engineVersion); + + AZStd::string platform = this->GetPlatform(); + metric.SetPlatform(platform, ""); + + AZStd::vector gemNames; + GetActiveAWSGems(gemNames); + for (AZStd::string& gemName : gemNames) + { + metric.AddActiveGem(gemName); + } + } + + void AWSAttributionManager::SubmitMetric(AttributionMetric& metric) + { + AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = ServiceAPI::AWSAttributionRequestJob::GetDefaultConfig(); + SetApiEndpointAndRegion(config); + + ServiceAPI::AWSAttributionRequestJob* requestJob = ServiceAPI::AWSAttributionRequestJob::Create( + [this](ServiceAPI::AWSAttributionRequestJob* successJob) + { + AZ_UNUSED(successJob); + + UpdateLastSend(); + AZ_Printf("AWSAttributionManager", "AWSAttribution metric submit success"); + + }, {}, config); + + requestJob->parameters.metric = metric; + requestJob->Start(); + } + +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp new file mode 100644 index 0000000000..6ad322995e --- /dev/null +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp @@ -0,0 +1,106 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include + +#pragma warning(disable : 4996) + +namespace AWSCore +{ + AttributionMetric::AttributionMetric(const AZStd::string& timestamp) + : m_version("1.1") + , m_timestamp(timestamp) + { + } + + AttributionMetric::AttributionMetric() + : m_version("1.1") + { + m_timestamp = AttributionMetric::GenerateTimeStamp(); + } + + void AttributionMetric::SetO3DEVersion(const AZStd::string& version) + { + m_o3deVersion = version; + } + + void AttributionMetric::SetPlatform(const AZStd::string& platform, const AZStd::string& platformVersion) + { + m_platform = platform; + m_platformVersion = platformVersion; + } + + void AttributionMetric::AddActiveGem(const AZStd::string& gemName) + { + m_activeAWSGems.push_back(gemName); + } + + AZStd::string AttributionMetric::SerializeToJson() + { + std::stringstream stringStream; + AWSCore::JsonOutputStream jsonStream{stringStream}; + AWSCore::JsonWriter writer{jsonStream}; + + SerializeToJson(writer); + + return stringStream.str().c_str(); + } + + bool AttributionMetric::SerializeToJson(AWSCore::JsonWriter& writer) const + { + bool ok = true; + ok = ok && writer.StartObject(); + + writer.Write(AwsAttributionAttributeKeyVersion, m_version.c_str()); + writer.Write(AwsAttributionAttributeKeyO3DEVersion, m_o3deVersion.c_str()); + writer.Write(AwsAttributionAttributeKeyPlatform, m_platform.c_str()); + writer.Write(AwsAttributionAttributeKeyPlatformVersion, m_platformVersion.c_str()); + + if (m_activeAWSGems.size() > 0) + { + writer.Key(AwsAttributionAttributeKeyActiveAWSGems); + writer.StartArray(); // to store Array of objects + for (auto& iter : m_activeAWSGems) + { + writer.String(iter.c_str()); + } + writer.EndArray(); + } + + writer.Write(AwsAttributionAttributeKeyTimestamp, m_timestamp.c_str()); + + ok = ok && writer.EndObject(); + return ok; + } + + bool AttributionMetric::ReadFromJson(rapidjson::Value& metricsObjVal) + { + AZ_UNUSED(metricsObjVal); + return false; + } + + AZStd::string AttributionMetric::GenerateTimeStamp() + { + // Timestamp format is using the UTC ISO8601 format + // TODO: Move to a general util as Metrics has similar requirement + time_t now; + time(&now); + char buffer[50]; + strftime(buffer, sizeof(buffer), "%FT%TZ", gmtime(&now)); + + return buffer; + } + +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp new file mode 100644 index 0000000000..ea388972d3 --- /dev/null +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp @@ -0,0 +1,81 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace AWSCore +{ + + AWSAttributionSystemComponent::AWSAttributionSystemComponent() + : m_manager(AZStd::make_unique()) + { + } + + void AWSAttributionSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class()->Version(0); + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("AWSCoreAttributions", "Generates operation metrics for AWSCore gem") + ->ClassElement(AZ::Edit::ClassElements::EditorData, ""); + } + } + } + + void AWSAttributionSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("AWSCoreAttributionService")); + } + + void AWSAttributionSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("AWSCoreAttributionService")); + } + + void AWSAttributionSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("AWSCoreService")); + } + + void AWSAttributionSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + AZ_UNUSED(dependent); + } + + void AWSAttributionSystemComponent::Init() + { + // load config if required - ie check if attributions should be generated and pass to manager + m_manager->Init(); + } + + void AWSAttributionSystemComponent::Activate() + { + m_manager->MetricCheck(); + } + + void AWSAttributionSystemComponent::Deactivate() + { + m_manager.reset(); + } + +} // namespace AWSCore + diff --git a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp new file mode 100644 index 0000000000..affa1ad69c --- /dev/null +++ b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp @@ -0,0 +1,85 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include + +#include + +using namespace AWSCore; + +namespace AWSCoreUnitTest +{ + class JsonReaderMock + : public AWSCore::JsonReader + { + public: + MOCK_METHOD0(Ignore, bool()); + MOCK_METHOD1(Accept, bool(bool& target)); + MOCK_METHOD1(Accept, bool(AZStd::string& target)); + MOCK_METHOD1(Accept, bool(int& target)); + MOCK_METHOD1(Accept, bool(unsigned& target)); + MOCK_METHOD1(Accept, bool(int64_t& target)); + MOCK_METHOD1(Accept, bool(uint64_t& target)); + MOCK_METHOD1(Accept, bool(double& target)); + MOCK_METHOD1(Accept, bool(AWSCore::JsonKeyHandler keyHandler)); + MOCK_METHOD1(Accept, bool(AWSCore::JsonArrayHandler arrayHandler)); + }; + + class AWSAttributionServiceApiTest + : public UnitTest::ScopedAllocatorSetupFixture + { + public: + testing::NiceMock JsonReader; + }; + + TEST_F(AWSAttributionServiceApiTest, AWSAtrributionSuccessResponse_Serialization) + { + ServiceAPI::AWSAtrributionSuccessResponse response; + response.result = "ok"; + + EXPECT_CALL(JsonReader, Accept(response.result)).Times(1); + EXPECT_CALL(JsonReader, Ignore()).Times(0); + + response.OnJsonKey("statusCode", JsonReader); + } + + TEST_F(AWSAttributionServiceApiTest, AWSAtrributionSuccessResponse_Serialization_Ignore) + { + ServiceAPI::AWSAtrributionSuccessResponse response; + response.result = "ok"; + + EXPECT_CALL(JsonReader, Accept(response.result)).Times(0); + EXPECT_CALL(JsonReader, Ignore()).Times(1); + + response.OnJsonKey("", JsonReader); + } + + TEST_F(AWSAttributionServiceApiTest, BuildRequestBody_PostProducerEventsRequest_SerializedMetricsQueue) + { + ServiceAPI::AWSAttributionRequest request; + request.parameters.metric = AttributionMetric(); + + AWSCore::RequestBuilder requestBuilder{}; + EXPECT_TRUE(request.parameters.BuildRequest(requestBuilder)); + std::shared_ptr bodyContent = requestBuilder.GetBodyContent(); + EXPECT_TRUE(bodyContent != nullptr); + + AZStd::string bodyString; + std::istreambuf_iterator eos; + bodyString = AZStd::string{ std::istreambuf_iterator(*bodyContent), eos }; + AZ_Printf("AWSAttributionServiceApiTest", bodyString.c_str()); + EXPECT_TRUE(bodyString.find(AZStd::string::format("{\"%s\":\"1.1\"", AwsAttributionAttributeKeyVersion)) != AZStd::string::npos); + } +} diff --git a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp new file mode 100644 index 0000000000..298c250086 --- /dev/null +++ b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp @@ -0,0 +1,414 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace AWSCore; + +namespace AWSAttributionUnitTest +{ + class ModuleDataMock: + public AZ::ModuleData + { + public: + AZStd::shared_ptr m_entity; + ModuleDataMock(AZStd::string name) + { + m_entity = AZStd::make_shared(); + m_entity->SetName(name); + } + virtual ~ModuleDataMock() + { + m_entity.reset(); + } + + AZ::DynamicModuleHandle* GetDynamicModuleHandle() const override + { + return nullptr; + } + /// Get the handle to the module class + AZ::Module* GetModule() const override + { + return nullptr; + } + /// Get the entity this module uses as a System Entity + AZ::Entity* GetEntity() const override + { + return m_entity.get(); + } + /// Get the debug name of the module + const char* GetDebugName() const override + { + return m_entity->GetName().c_str(); + } + }; + + class ModuleManagerRequestBusMock + : public AZ::ModuleManagerRequestBus::Handler + { + public: + + void EnumerateModulesMock(AZ::ModuleManagerRequests::EnumerateModulesCallback perModuleCallback) + { + auto data = ModuleDataMock("AWSCore.Editor.dll"); + perModuleCallback(data); + data = ModuleDataMock("AWSClientAuth.so"); + perModuleCallback(data); + } + + ModuleManagerRequestBusMock() + { + AZ::ModuleManagerRequestBus::Handler::BusConnect(); + ON_CALL(*this, EnumerateModules(testing::_)).WillByDefault(testing::Invoke(this, &ModuleManagerRequestBusMock::EnumerateModulesMock)); + } + + ~ModuleManagerRequestBusMock() + { + AZ::ModuleManagerRequestBus::Handler::BusDisconnect(); + } + + MOCK_METHOD1(EnumerateModules, void(AZ::ModuleManagerRequests::EnumerateModulesCallback perModuleCallback)); + MOCK_METHOD3(LoadDynamicModule, AZ::ModuleManagerRequests::LoadModuleOutcome(const char* modulePath, AZ::ModuleInitializationSteps lastStepToPerform, bool maintainReference)); + MOCK_METHOD3(LoadDynamicModules, AZ::ModuleManagerRequests::LoadModulesResult(const AZ::ModuleDescriptorList& modules, AZ::ModuleInitializationSteps lastStepToPerform, bool maintainReferences)); + MOCK_METHOD2(LoadStaticModules, AZ::ModuleManagerRequests::LoadModulesResult(AZ::CreateStaticModulesCallback staticModulesCb, AZ::ModuleInitializationSteps lastStepToPerform)); + MOCK_METHOD1(IsModuleLoaded, bool(const char* modulePath)); + }; + + class AWSAttributionManagerMock + : public AWSAttributionManager + { + public: + using AWSAttributionManager::SubmitMetric; + using AWSAttributionManager::UpdateMetric; + using AWSAttributionManager::SetApiEndpointAndRegion; + + + AWSAttributionManagerMock() + { + ON_CALL(*this, SubmitMetric(testing::_)).WillByDefault(testing::Invoke(this, &AWSAttributionManagerMock::SubmitMetricMock)); + } + + MOCK_METHOD1(SubmitMetric, void(AttributionMetric& metric)); + + void SubmitMetricMock(AttributionMetric& metric) + { + AZ_UNUSED(metric); + UpdateLastSend(); + } + }; + + class AttributionManagerTest + : public AWSCoreFixture + { + public: + + virtual ~AttributionManagerTest() = default; + + protected: + AZStd::shared_ptr m_serializeContext; + AZStd::unique_ptr m_registrationContext; + AZStd::shared_ptr m_settingsRegistry; + AZStd::unique_ptr m_jobContext; + AZStd::unique_ptr m_jobCancelGroup; + AZStd::unique_ptr m_jobManager; + AZStd::array m_resolvedSettingsPath; + ModuleManagerRequestBusMock m_moduleManagerRequestBusMock; + + void SetUp() override + { + AWSCoreFixture::SetUp(); + + char rootPath[AZ_MAX_PATH_LEN]; + AZ::Utils::GetExecutableDirectory(rootPath, AZ_MAX_PATH_LEN); + m_localFileIO->SetAlias("@user@", AZ_TRAIT_TEST_ROOT_FOLDER); + + m_localFileIO->ResolvePath("@user@/Registry/", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size()); + AZ::IO::SystemFile::CreateDir(m_resolvedSettingsPath.data()); + + m_localFileIO->ResolvePath("@user@/Registry/editor_aws_preferences.setreg", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size()); + + m_serializeContext = AZStd::make_unique(); + + AZ::JsonSystemComponent::Reflect(m_registrationContext.get()); + + m_settingsRegistry = AZStd::make_unique(); + + m_settingsRegistry->SetContext(m_serializeContext.get()); + m_settingsRegistry->SetContext(m_registrationContext.get()); + + AZ::SettingsRegistry::Register(m_settingsRegistry.get()); + + AZ::JobManagerDesc jobManagerDesc; + AZ::JobManagerThreadDesc threadDesc; + + m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc)); + m_jobCancelGroup.reset(aznew AZ::JobCancelGroup()); + jobManagerDesc.m_workerThreads.push_back(threadDesc); + m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup)); + AZ::JobContext::SetGlobalContext(m_jobContext.get()); + } + + void TearDown() override + { + AZ::JobContext::SetGlobalContext(nullptr); + m_jobContext.reset(); + m_jobCancelGroup.reset(); + m_jobManager.reset(); + + AZ::SettingsRegistry::Unregister(m_settingsRegistry.get()); + + m_settingsRegistry.reset(); + m_serializeContext.reset(); + m_registrationContext.reset(); + + m_localFileIO->ResolvePath("@user@/Registry/", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size()); + AZ::IO::SystemFile::DeleteDir(m_resolvedSettingsPath.data()); + + delete AZ::IO::FileIOBase::GetInstance(); + AZ::IO::FileIOBase::SetInstance(nullptr); + + AWSCoreFixture::TearDown(); + } + }; + + TEST_F(AttributionManagerTest, MetricsSettings_AttributionDisabled_SkipsSend) + { + // GIVEN + AWSAttributionManagerMock manager; + manager.Init(); + + CreateFile(m_resolvedSettingsPath.data(), R"({ + "Amazon": { + "AWS": { + "Preferences": { + "AWSAttributionEnabled": false, + "AWSAttributionDelaySeconds": 30 + } + } + } + })"); + + EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(0); + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(0); + + // WHEN + manager.MetricCheck(); + + // THEN + m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + AZ::u64 timeStamp = 0; + m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"); + ASSERT_TRUE(timeStamp == 0); + + RemoveFile(m_resolvedSettingsPath.data()); + } + + TEST_F(AttributionManagerTest, AttributionEnabled_NoPreviousTimeStamp_SendSuccess) + { + // GIVEN + AWSAttributionManagerMock manager; + manager.Init(); + + CreateFile(m_resolvedSettingsPath.data(), R"({ + "Amazon": { + "AWS": { + "Preferences": { + "AWSAttributionEnabled": true, + "AWSAttributionDelaySeconds": 30, + } + } + } + })"); + + EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1); + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1); + + // WHEN + manager.MetricCheck(); + + // THEN + m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + AZ::u64 timeStamp = 0; + m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"); + ASSERT_TRUE(timeStamp > 0); + + + RemoveFile(m_resolvedSettingsPath.data()); + } + + TEST_F(AttributionManagerTest, AttributionEnabled_ValidPreviousTimeStamp_SendSuccess) + { + // GIVEN + AWSAttributionManagerMock manager; + manager.Init(); + + CreateFile(m_resolvedSettingsPath.data(), R"({ + "Amazon": { + "AWS": { + "Preferences": { + "AWSAttributionEnabled": true, + "AWSAttributionDelaySeconds": 30, + "AWSAttributionLastTimeStamp": 629400 + } + } + } + })"); + + EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1); + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1); + + // WHEN + manager.MetricCheck(); + + // THEN + m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + AZ::u64 timeStamp = 0; + m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"); + ASSERT_TRUE(timeStamp > 0); + + RemoveFile(m_resolvedSettingsPath.data()); + } + + TEST_F(AttributionManagerTest, AttributionEnabled_DelayNotSatisfied_SendFail) + { + // GIVEN + AWSAttributionManagerMock manager; + manager.Init(); + + + CreateFile(m_resolvedSettingsPath.data(), R"({ + "Amazon": { + "AWS": { + "Preferences": { + "AWSAttributionEnabled": true, + "AWSAttributionDelaySeconds": 300, + "AWSAttributionLastTimeStamp": 0 + } + } + } + })"); + + AZ::u64 delayInSeconds = AZStd::chrono::duration_cast(AZStd::chrono::system_clock::now().time_since_epoch()).count(); + ASSERT_TRUE(m_settingsRegistry->Set("/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp", delayInSeconds)); + + EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1); + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1); + + // WHEN + manager.MetricCheck(); + + // THEN + m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + AZ::u64 timeStamp = 0; + m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"); + ASSERT_TRUE(timeStamp == delayInSeconds); + + RemoveFile(m_resolvedSettingsPath.data()); + } + + TEST_F(AttributionManagerTest, AttributionEnabledNotFound_SendSuccess) + { + // GIVEN + AWSAttributionManagerMock manager; + manager.Init(); + + CreateFile(m_resolvedSettingsPath.data(), R"({ + "Amazon": { + "AWS": { + "Preferences": { + } + } + } + })"); + + EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1); + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1); + + // WHEN + manager.MetricCheck(); + + // THEN + m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ""); + AZ::u64 timeStamp = 0; + m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp"); + ASSERT_TRUE(timeStamp != 0); + + RemoveFile(m_resolvedSettingsPath.data()); + } + + TEST_F(AttributionManagerTest, SetApiEndpointAndRegion_Success) + { + // GIVEN + AWSAttributionManagerMock manager; + AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = aznew AWSCore::ServiceAPI::AWSAttributionRequestJob::Config(); + + // WHEN + manager.SetApiEndpointAndRegion(config); + + // THEN + ASSERT_TRUE(config->region == Aws::Region::US_WEST_2); + ASSERT_TRUE(config->endpointOverride->find("execute-api.us-west-2.amazonaws.com") != Aws::String::npos); + + delete config; + } + + TEST_F(AttributionManagerTest, UpdateMetric_Success) + { + // GIVEN + AWSAttributionManagerMock manager; + AttributionMetric metric; + + AZStd::array engineJsonPath; + m_localFileIO->ResolvePath("@user@/Registry/engine.json", engineJsonPath.data(), engineJsonPath.size()); + CreateFile(engineJsonPath.data(), R"({"O3DEVersion": "1.0.0.0"})"); + + m_localFileIO->ResolvePath("@user@/Registry/", engineJsonPath.data(), engineJsonPath.size()); + m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder, engineJsonPath.data()); + + EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1); + + // WHEN + manager.UpdateMetric(metric); + + // THEN + AZStd::string serializedMetricValue = metric.SerializeToJson(); + ASSERT_TRUE(serializedMetricValue.find("\"o3de_version\":\"1.0.0.0\"") != AZStd::string::npos); + ASSERT_TRUE(serializedMetricValue.find(AZ::GetPlatformName(AZ::g_currentPlatform)) != AZStd::string::npos); + ASSERT_TRUE(serializedMetricValue.find("AWSCore.Editor") != AZStd::string::npos); + ASSERT_TRUE(serializedMetricValue.find("AWSClientAuth") != AZStd::string::npos); + + RemoveFile(engineJsonPath.data()); + } + +} // namespace AWSCoreUnitTest diff --git a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp new file mode 100644 index 0000000000..c93b8bb08e --- /dev/null +++ b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp @@ -0,0 +1,50 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include + +namespace AWSCore +{ + using AttributionMetricTest = UnitTest::ScopedAllocatorSetupFixture; + + TEST_F(AttributionMetricTest, Contruction_Test) + { + AZStd::string timestamp = AttributionMetric::GenerateTimeStamp(); + AttributionMetric metric(timestamp); + + AZStd::string serializedMetric = AZStd::string::format( + "{\"version\":\"1.1\",\"o3de_version\":\"\",\"platform\":\"\",\"platform_version\":\"\",\"timestamp\":\"%s\"}", timestamp.c_str()); + ASSERT_EQ(metric.SerializeToJson(), serializedMetric); + } + + TEST_F(AttributionMetricTest, AddActiveGems) + { + AZStd::string timestamp = AttributionMetric::GenerateTimeStamp(); + AttributionMetric metric(timestamp); + + AZStd::string gem1 = "AWSGem1"; + AZStd::string gem2 = "AWSGem2"; + + metric.AddActiveGem(gem1); + metric.AddActiveGem(gem2); + + AZStd::string serializedMetric = AZStd::string::format( + "{\"version\":\"1.1\",\"o3de_version\":\"\",\"platform\":\"\",\"platform_version\":\"\",\"aws_gems\":[\"%s\",\"%s\"],\"timestamp\":\"%s\"}", + gem1.c_str(), gem2.c_str(), timestamp.c_str()); + + AZStd::string actualValue = metric.SerializeToJson(); + ASSERT_EQ(actualValue, serializedMetric); + } + +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp new file mode 100644 index 0000000000..4419c78467 --- /dev/null +++ b/Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp @@ -0,0 +1,132 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace AWSCore; + +namespace AWSCoreUnitTest +{ + class AWSCoreSystemComponentMock : public AZ::Component + { + public: + AZ_COMPONENT(AWSCoreSystemComponentMock, "{5F48030D-EB59-4820-BC65-69EC7CC6C119}"); + + static void Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class()->Version(0); + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("AWSCoreMock", "Adds core support for working with AWS") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true); + } + } + } + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("AWSCoreService")); + } + + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + AZ_UNUSED(incompatible); + } + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + AZ_UNUSED(required); + } + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + AZ_UNUSED(dependent); + } + + ~AWSCoreSystemComponentMock() = default; + + MOCK_METHOD0(Init, void()); + MOCK_METHOD0(Activate, void()); + MOCK_METHOD0(Deactivate, void()); + }; + + class AWSAttributionSystemComponentTest : public AWSCoreFixture + { + void SetUp() override + { + AWSCoreFixture::SetUp(); + m_serializeContext = AZStd::make_unique(); + m_serializeContext->CreateEditContext(); + m_behaviorContext = AZStd::make_unique(); + + m_awsCoreComponentDescriptor.reset(AWSCoreSystemComponentMock::CreateDescriptor()); + m_awsCoreComponentDescriptor->Reflect(m_serializeContext.get()); + m_awsCoreComponentDescriptor->Reflect(m_behaviorContext.get()); + + m_componentDescriptor.reset(AWSAttributionSystemComponent::CreateDescriptor()); + m_componentDescriptor->Reflect(m_serializeContext.get()); + m_componentDescriptor->Reflect(m_behaviorContext.get()); + + m_entity = aznew AZ::Entity(); + m_awsCoreSystemComponentMock = aznew testing::NiceMock(); + m_entity->AddComponent(m_awsCoreSystemComponentMock); + m_attributionSystemsComponent.reset(m_entity->CreateComponent()); + } + + void TearDown() override + { + m_entity->Deactivate(); + m_entity->RemoveComponent(m_attributionSystemsComponent.get()); + m_entity->RemoveComponent(m_awsCoreSystemComponentMock); + delete m_entity; + m_entity = nullptr; + + m_attributionSystemsComponent.reset(); + delete m_awsCoreSystemComponentMock; + m_awsCoreComponentDescriptor.reset(); + m_componentDescriptor.reset(); + m_behaviorContext.reset(); + m_serializeContext.reset(); + AWSCoreFixture::TearDown(); + } + + public: + AZStd::unique_ptr m_attributionSystemsComponent; + testing::NiceMock* m_awsCoreSystemComponentMock; + AZ::Entity* m_entity; + + private: + AZStd::unique_ptr m_serializeContext; + AZStd::unique_ptr m_behaviorContext; + AZStd::unique_ptr m_componentDescriptor; + AZStd::unique_ptr m_awsCoreComponentDescriptor; + }; + + TEST_F(AWSAttributionSystemComponentTest, SystemComponentInitActivate_Success) + { + m_entity->Init(); + m_entity->Activate(); + } +} + + diff --git a/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h b/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h index 1810af9c82..d921ffaf07 100644 --- a/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h +++ b/Gems/AWSCore/Code/Tests/TestFramework/AWSCoreFixture.h @@ -127,13 +127,40 @@ public: void TearDown() override { AZ::IO::FileIOBase::SetInstance(nullptr); - delete m_localFileIO; - AZ::IO::FileIOBase::SetInstance(m_otherFileIO); + + if (m_otherFileIO) + { + delete m_localFileIO; + AZ::IO::FileIOBase::SetInstance(m_otherFileIO); + } AZ::AllocatorInstance::Destroy(); AZ::AllocatorInstance::Destroy(); } + bool CreateFile(const AZStd::string& filePath, const AZStd::string& content) + { + AZ::IO::HandleType fileHandle; + if (!m_localFileIO->Open(filePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText, fileHandle)) + { + return false; + } + + m_localFileIO->Write(fileHandle, content.c_str(), content.size()); + m_localFileIO->Close(fileHandle); + return true; + } + + bool RemoveFile(const AZStd::string& filePath) + { + if (m_localFileIO->Exists(filePath.c_str())) + { + return m_localFileIO->Remove(filePath.c_str()); + } + + return true; + } + AZ::IO::FileIOBase* m_localFileIO = nullptr; private: diff --git a/Gems/AWSCore/Code/awscore_editor_files.cmake b/Gems/AWSCore/Code/awscore_editor_files.cmake index 13bfbb6102..6e16fc7d27 100644 --- a/Gems/AWSCore/Code/awscore_editor_files.cmake +++ b/Gems/AWSCore/Code/awscore_editor_files.cmake @@ -11,6 +11,11 @@ set(FILES Include/Private/AWSCoreEditorSystemComponent.h + Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h + Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h + Include/Private/Editor/Attribution/AWSCoreAttributionManager.h + Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h + Include/Private/Editor/Attribution/AWSAttributionServiceApi.h Include/Private/Editor/AWSCoreEditorManager.h Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h @@ -18,6 +23,10 @@ set(FILES Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h Source/AWSCoreEditorSystemComponent.cpp Source/Editor/AWSCoreEditorManager.cpp + Source/Editor/Attribution/AWSCoreAttributionMetric.cpp + Source/Editor/Attribution/AWSCoreAttributionManager.cpp + Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp + Source/Editor/Attribution/AWSAttributionServiceApi.cpp Source/Editor/UI/AWSCoreEditorMenu.cpp Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp ) diff --git a/Gems/AWSCore/Code/awscore_editor_tests_files.cmake b/Gems/AWSCore/Code/awscore_editor_tests_files.cmake index ff89b6b5bd..bba830d5d1 100644 --- a/Gems/AWSCore/Code/awscore_editor_tests_files.cmake +++ b/Gems/AWSCore/Code/awscore_editor_tests_files.cmake @@ -11,6 +11,10 @@ set(FILES Tests/AWSCoreEditorSystemComponentTest.cpp + Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp + Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp + Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp + Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp Tests/Editor/UI/AWSCoreEditorMenuTest.cpp Tests/Editor/UI/AWSCoreEditorUIFixture.h Tests/Editor/UI/AWSCoreResourceMappingToolActionTest.cpp From aeaf1bcdbe6768ba0f4ef3e7afd603a899d3474c Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 4 Jun 2021 21:29:36 -0700 Subject: [PATCH 134/153] Fix engine settings not populating or saving * Allow multiple settings to be registered at once * Old manifests versions may not have default_third_party_folder --- .../ProjectManager/Source/PythonBindings.cpp | 4 +- scripts/o3de/o3de/register.py | 50 +++++++++---------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 5f4bb833d8..d7d0414c1f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -384,7 +384,9 @@ namespace O3DE::ProjectManager engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String(o3deData["default_third_party_folder"]); + + pybind11::str defaultThirdPartyFolder = m_manifest.attr("get_o3de_third_party_folder")(); + engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"default_third_party_folder", Py_To_String(defaultThirdPartyFolder)); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 4e73edca7f..b3a6a1e44c 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -580,65 +580,65 @@ def register(engine_path: str or pathlib.Path = None, if not project_path: logger.error(f'Project path cannot be empty.') return 1 - result = register_project_path(json_data, project_path, remove, engine_path) + result = result or register_project_path(json_data, project_path, remove, engine_path) - elif isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): + if isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): if not gem_path: logger.error(f'Gem path cannot be empty.') return 1 - result = register_gem_path(json_data, gem_path, remove, + result = result or register_gem_path(json_data, gem_path, remove, external_subdir_engine_path, external_subdir_project_path) - elif isinstance(external_subdir_path, str) or isinstance(external_subdir_path, pathlib.PurePath): + if isinstance(external_subdir_path, str) or isinstance(external_subdir_path, pathlib.PurePath): if not external_subdir_path: logger.error(f'External Subdirectory path is None.') return 1 - result = register_external_subdirectory(json_data, external_subdir_path, remove, + result = result or register_external_subdirectory(json_data, external_subdir_path, remove, external_subdir_engine_path, external_subdir_project_path) - elif isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): + if isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): if not template_path: logger.error(f'Template path cannot be empty.') return 1 - result = register_template_path(json_data, template_path, remove, engine_path) + result = result or register_template_path(json_data, template_path, remove, engine_path) - elif isinstance(restricted_path, str) or isinstance(restricted_path, pathlib.PurePath): + if isinstance(restricted_path, str) or isinstance(restricted_path, pathlib.PurePath): if not restricted_path: logger.error(f'Restricted path cannot be empty.') return 1 - result = register_restricted_path(json_data, restricted_path, remove, engine_path) + result = result or register_restricted_path(json_data, restricted_path, remove, engine_path) - elif isinstance(repo_uri, str) or isinstance(repo_uri, pathlib.PurePath): + if isinstance(repo_uri, str) or isinstance(repo_uri, pathlib.PurePath): if not repo_uri: logger.error(f'Repo URI cannot be empty.') return 1 - result = register_repo(json_data, repo_uri, remove) + result = result or register_repo(json_data, repo_uri, remove) - elif isinstance(default_engines_folder, str) or isinstance(default_engines_folder, pathlib.PurePath): - result = register_default_engines_folder(json_data, default_engines_folder, remove) + if isinstance(default_engines_folder, str) or isinstance(default_engines_folder, pathlib.PurePath): + result = result or register_default_engines_folder(json_data, default_engines_folder, remove) - elif isinstance(default_projects_folder, str) or isinstance(default_projects_folder, pathlib.PurePath): - result = register_default_projects_folder(json_data, default_projects_folder, remove) + if isinstance(default_projects_folder, str) or isinstance(default_projects_folder, pathlib.PurePath): + result = result or register_default_projects_folder(json_data, default_projects_folder, remove) - elif isinstance(default_gems_folder, str) or isinstance(default_gems_folder, pathlib.PurePath): - result = register_default_gems_folder(json_data, default_gems_folder, remove) + if isinstance(default_gems_folder, str) or isinstance(default_gems_folder, pathlib.PurePath): + result = result or register_default_gems_folder(json_data, default_gems_folder, remove) - elif isinstance(default_templates_folder, str) or isinstance(default_templates_folder, pathlib.PurePath): - result = register_default_templates_folder(json_data, default_templates_folder, remove) + if isinstance(default_templates_folder, str) or isinstance(default_templates_folder, pathlib.PurePath): + result = result or register_default_templates_folder(json_data, default_templates_folder, remove) - elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): - result = register_default_restricted_folder(json_data, default_restricted_folder, remove) + if isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): + result = result or register_default_restricted_folder(json_data, default_restricted_folder, remove) - elif default_third_party_folder: - result = register_default_third_party_folder(json_data, default_third_party_folder, remove) + if isinstance(default_third_party_folder, str) or isinstance(default_third_party_folder, pathlib.PurePath): + result = result or register_default_third_party_folder(json_data, default_third_party_folder, remove) # engine is done LAST # Now that everything that could have an engine context is done, if the engine is supplied that means this is # registering the engine itself - elif isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): + if isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 - result = register_engine_path(json_data, engine_path, remove, force) + result = result or register_engine_path(json_data, engine_path, remove, force) if not result: manifest.save_o3de_manifest(json_data) From 1ffcfa07e6126c60e035a65f77bb7107d21b86dc Mon Sep 17 00:00:00 2001 From: Ibtehaj Nadeem <81370835+ibtehajn@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:53:07 +0100 Subject: [PATCH 135/153] Remove Jenkins failure notifications (#958) Remove Jenkins failure notifications --- scripts/build/Jenkins/Jenkinsfile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 3cf7d92ba6..1bce2988bf 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -578,14 +578,12 @@ finally { ) } node('controller') { - emailRecipients = [[$class: 'RequesterRecipientProvider']] - if (env.WATCHED_BRANCHES.tokenize(',').contains(branchName)) { - emailRecipients.add([$class: 'CulpritsRecipientProvider']) - } step([ - $class: 'Mailer', - notifyEveryUnstableBuild: true, - recipients: emailextrecipients(emailRecipients) + $class: 'Mailer', + notifyEveryUnstableBuild: true, + recipients: emailextrecipients([ + [$class: 'RequesterRecipientProvider'] + ]) ]) } } catch(Exception e) { From 5b940e8ed671034fa1ffb5e6950e752d88542ef2 Mon Sep 17 00:00:00 2001 From: Hasareej <82398396+Hasareej@users.noreply.github.com> Date: Mon, 7 Jun 2021 13:32:13 +0100 Subject: [PATCH 136/153] Viewport Ui Cluster Locked State Overlay (#1139) * Viewport Ui Cluster Locked State Overlay * PR feedback changes. --- .../img/UI20/toolbar/Locked_Status.svg | 12 ++++ .../AzQtComponents/Components/resources.qrc | 3 +- .../EditorTransformComponentSelection.cpp | 3 + .../ViewportUi/ViewportUiCluster.cpp | 55 +++++++++++++++++++ .../ViewportUi/ViewportUiCluster.h | 4 ++ .../ViewportUi/ViewportUiDisplay.cpp | 8 +++ .../ViewportUi/ViewportUiDisplay.h | 1 + .../ViewportUi/ViewportUiManager.cpp | 10 ++++ .../ViewportUi/ViewportUiManager.h | 1 + .../ViewportUi/ViewportUiRequestBus.h | 2 + 10 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/Locked_Status.svg diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/Locked_Status.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/Locked_Status.svg new file mode 100644 index 0000000000..2612059dce --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/toolbar/Locked_Status.svg @@ -0,0 +1,12 @@ + + + Icon / Locked Status + + + + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc index 00fa95d094..7070bd372b 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc @@ -356,7 +356,8 @@ img/UI20/toolbar/Load.svg img/UI20/toolbar/Local.svg img/UI20/toolbar/Locked.svg - img/UI20/toolbar/LUA.svg + img/UI20/toolbar/Locked_Status.svg + img/UI20/toolbar/LUA.svg img/UI20/toolbar/Material.svg img/UI20/toolbar/Measure.svg img/UI20/toolbar/Move.svg diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index db321d6818..5603c1a0f7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -2646,6 +2646,9 @@ namespace AzToolsFramework m_spaceCluster.m_spaceLock = ReferenceFrame::World; } } + ViewportUi::ViewportUiRequestBus::Event( + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterButtonLocked, + m_spaceCluster.m_spaceClusterId, buttonId, m_spaceCluster.m_spaceLock.has_value()); }; m_spaceCluster.m_spaceSelectionHandler = AZ::Event::Handler(onButtonClicked); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.cpp index 79744f1dbf..d452d47508 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.cpp @@ -108,6 +108,61 @@ namespace AzToolsFramework::ViewportUi::Internal m_widgetCallbacks.Update(); } + void ViewportUiCluster::SetButtonLocked(const ButtonId buttonId, const bool isLocked) + { + const auto& buttons = m_buttonGroup->GetButtons(); + + // unlocked previously locked button + if (m_lockedButtonId.has_value() && isLocked) + { + // find the button to extract the old icon (without overlay) + auto findLocked = [this](const Button* button) { return (button->m_buttonId == m_lockedButtonId); }; + if (auto lockedButtonIt = AZStd::find_if(buttons.begin(), buttons.end(), findLocked); lockedButtonIt != buttons.end()) + { + // get the action corresponding to the lockedButtonId + if (auto actionEntry = m_buttonActionMap.find(m_lockedButtonId.value()); actionEntry != m_buttonActionMap.end()) + { + // remove the overlay + auto action = actionEntry->second; + action->setIcon(QIcon(QString((*lockedButtonIt)->m_icon.c_str()))); + } + } + } + + auto found = [buttonId](Button* button) { return (button->m_buttonId == buttonId); }; + if (auto buttonIt = AZStd::find_if(buttons.begin(), buttons.end(), found); buttonIt != buttons.end()) + { + QIcon newIcon; + + if (isLocked) + { + // overlay the locked icon ontop of the button's icon + QPixmap comboPixmap(24, 24); + comboPixmap.fill(Qt::transparent); + QPixmap firstImage(QString((*buttonIt)->m_icon.c_str())); + QPixmap secondImage(QString(":/stylesheet/img/UI20/toolbar/Locked_Status.svg")); + + QPainter painter(&comboPixmap); + painter.drawPixmap(0, 0, firstImage); + painter.drawPixmap(0, 0, secondImage); + newIcon.addPixmap(comboPixmap); + m_lockedButtonId = buttonId; + } + else + { + // remove the overlay + newIcon = QIcon(QString((*buttonIt)->m_icon.c_str())); + m_lockedButtonId = AZStd::nullopt; + } + + if (auto actionEntry = m_buttonActionMap.find(buttonId); actionEntry != m_buttonActionMap.end()) + { + auto action = actionEntry->second; + action->setIcon(newIcon); + } + } + } + ViewportUiWidgetCallbacks ViewportUiCluster::GetWidgetCallbacks() { return m_widgetCallbacks; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.h index 4f738177ea..027a201a9c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiCluster.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace AzToolsFramework::ViewportUi::Internal { @@ -38,6 +39,8 @@ namespace AzToolsFramework::ViewportUi::Internal void RemoveButton(ButtonId buttonId); //! Updates all registered actions. void Update(); + //! Adds a locked overlay to the button's icon. + void SetButtonLocked(ButtonId buttonId, bool isLocked); //! Returns the widget manager. ViewportUiWidgetCallbacks GetWidgetCallbacks(); @@ -52,5 +55,6 @@ namespace AzToolsFramework::ViewportUi::Internal AZStd::shared_ptr m_buttonGroup; //!< Data structure which the cluster will be displaying to the Viewport UI. AZStd::unordered_map> m_buttonActionMap; //!< Map for buttons to their corresponding actions. ViewportUiWidgetCallbacks m_widgetCallbacks; //!< Registers actions and manages updates. + AZStd::optional m_lockedButtonId = AZStd::nullopt; //!< Used to track the last button locked. }; } // namespace AzToolsFramework::ViewportUi::Internal diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index e9e7dcc1cc..3565d33174 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -100,6 +100,14 @@ namespace AzToolsFramework::ViewportUi::Internal } } + void ViewportUiDisplay::SetClusterButtonLocked(const ViewportUiElementId clusterId, const ButtonId buttonId, const bool isLocked) + { + if (auto viewportUiCluster = qobject_cast(GetViewportUiElement(clusterId).get())) + { + viewportUiCluster->SetButtonLocked(buttonId, isLocked); + } + } + void ViewportUiDisplay::RemoveClusterButton(ViewportUiElementId clusterId, ButtonId buttonId) { if (auto cluster = qobject_cast(GetViewportUiElement(clusterId).get())) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h index d46e01c978..19d04e63ff 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.h @@ -58,6 +58,7 @@ namespace AzToolsFramework::ViewportUi::Internal void AddCluster(AZStd::shared_ptr buttonGroup, Alignment align); void AddClusterButton(ViewportUiElementId clusterId, Button* button); + void SetClusterButtonLocked(ViewportUiElementId clusterId, ButtonId buttonId, bool isLocked); void RemoveClusterButton(ViewportUiElementId clusterId, ButtonId buttonId); void UpdateCluster(const ViewportUiElementId clusterId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp index 12c3b5c9bb..0668af383b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.cpp @@ -67,6 +67,16 @@ namespace AzToolsFramework::ViewportUi } } + void ViewportUiManager::SetClusterButtonLocked(const ClusterId clusterId, const ButtonId buttonId, const bool isLocked) + { + if (auto clusterIt = m_clusterButtonGroups.find(clusterId); clusterIt != m_clusterButtonGroups.end()) + { + auto cluster = clusterIt->second; + m_viewportUi->SetClusterButtonLocked(cluster->GetViewportUiElementId(), buttonId, isLocked); + UpdateButtonGroupUi(cluster.get()); + } + } + void ViewportUiManager::RegisterClusterEventHandler(const ClusterId clusterId, AZ::Event::Handler& handler) { if (auto clusterIt = m_clusterButtonGroups.find(clusterId); clusterIt != m_clusterButtonGroups.end()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h index 04a58cef65..14609ccc14 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiManager.h @@ -35,6 +35,7 @@ namespace AzToolsFramework::ViewportUi const SwitcherId CreateSwitcher(Alignment align) override; void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) override; void SetSwitcherActiveButton(SwitcherId switcherId, ButtonId buttonId) override; + void SetClusterButtonLocked(ClusterId clusterId, ButtonId buttonId, bool isLocked) override; const ButtonId CreateClusterButton(ClusterId clusterId, const AZStd::string& icon) override; const ButtonId CreateSwitcherButton( SwitcherId switcherId, const AZStd::string& icon, const AZStd::string& name = AZStd::string()) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h index 3879817ccb..a068ffe9ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiRequestBus.h @@ -65,6 +65,8 @@ namespace AzToolsFramework::ViewportUi virtual void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) = 0; //! Sets the active button of the switcher. This is the button which has a text label. virtual void SetSwitcherActiveButton(SwitcherId clusterId, ButtonId buttonId) = 0; + //! Adds a locked overlay to the cluster button's icon. + virtual void SetClusterButtonLocked(ClusterId clusterId, ButtonId buttonId, bool isLocked) = 0; //! Registers a new button onto a cluster. virtual const ButtonId CreateClusterButton(const ClusterId clusterId, const AZStd::string& icon) = 0; //! Registers a new button onto a switcher. From c751cda73d0831e87beeca09832ff134219f8a25 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 7 Jun 2021 13:07:17 +0000 Subject: [PATCH 137/153] Fix for variable that is only used in the debug config (#1166) --- .../Code/Source/Integration/Components/ActorComponent.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index f41ef165c8..b0065708fb 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -299,8 +299,7 @@ namespace EMotionFX void ActorComponent::OnAssetReady(AZ::Data::Asset asset) { m_configuration.m_actorAsset = asset; - Actor* actor = m_configuration.m_actorAsset->GetActor(); - AZ_Assert(m_configuration.m_actorAsset.IsReady() && actor, "Actor asset should be loaded and actor valid."); + AZ_Assert(m_configuration.m_actorAsset.IsReady() && m_configuration.m_actorAsset->GetActor(), "Actor asset should be loaded and actor valid."); CheckActorCreation(); } From cf8a6761bf91a0e098643a54dbe2882ed3cc21de Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 7 Jun 2021 14:50:49 +0100 Subject: [PATCH 138/153] Formatting-only change - Update Manipulator and Viewport AzToolsFramework files (#1143) * formatting changes to AzToolsFramework viewport related types + API comment style updates * minor format change - include ordering * improve formatting by moving comment * fix compile error and switch to use AZ_Printf * small polish changes after review feedback --- Code/Framework/AzCore/AzCore/std/math.h | 3 + .../AzFramework/Viewport/CameraInput.cpp | 36 +- .../ActionDispatcher.h | 2 +- .../AzManipulatorTestFrameworkUtils.h | 9 +- .../ImmediateModeActionDispatcher.h | 10 +- .../AzManipulatorTestFrameworkUtils.cpp | 6 +- .../DirectManipulatorViewportInteraction.cpp | 42 +- .../Source/ImmediateModeActionDispatcher.cpp | 14 +- .../Tests/BusCallTest.cpp | 35 +- .../Tests/DirectCallTest.cpp | 21 +- .../Tests/GridSnappingTest.cpp | 5 +- .../Tests/ViewportInteractionTest.cpp | 6 +- .../Tests/WorldSpaceBuilderTest.cpp | 83 +- .../Manipulators/AngularManipulator.cpp | 96 +- .../Manipulators/AngularManipulator.h | 115 +- .../Manipulators/BaseManipulator.cpp | 125 +- .../Manipulators/BaseManipulator.h | 323 ++-- .../Manipulators/BoxManipulatorRequestBus.h | 49 +- .../Manipulators/EditorVertexSelection.cpp | 834 ++++----- .../Manipulators/EditorVertexSelection.h | 296 +-- .../Manipulators/HoverSelection.h | 64 +- .../Manipulators/LineHoverSelection.cpp | 53 +- .../Manipulators/LineHoverSelection.h | 35 +- .../LineSegmentSelectionManipulator.cpp | 50 +- .../LineSegmentSelectionManipulator.h | 71 +- .../Manipulators/LinearManipulator.cpp | 97 +- .../Manipulators/LinearManipulator.h | 132 +- .../Manipulators/ManipulatorBus.h | 79 +- .../Manipulators/ManipulatorManager.cpp | 67 +- .../Manipulators/ManipulatorManager.h | 83 +- .../Manipulators/ManipulatorSnapping.cpp | 108 +- .../Manipulators/ManipulatorSnapping.h | 114 +- .../Manipulators/ManipulatorSpace.h | 22 +- .../Manipulators/ManipulatorView.cpp | 449 ++--- .../Manipulators/ManipulatorView.h | 319 ++-- .../Manipulators/MultiLinearManipulator.cpp | 58 +- .../Manipulators/MultiLinearManipulator.h | 29 +- .../Manipulators/PlanarManipulator.cpp | 82 +- .../Manipulators/PlanarManipulator.h | 108 +- .../Manipulators/RotationManipulators.cpp | 57 +- .../Manipulators/RotationManipulators.h | 35 +- .../Manipulators/ScaleManipulators.cpp | 71 +- .../Manipulators/ScaleManipulators.h | 40 +- .../Manipulators/SelectionManipulator.cpp | 35 +- .../Manipulators/SelectionManipulator.h | 69 +- .../Manipulators/SplineHoverSelection.cpp | 37 +- .../Manipulators/SplineHoverSelection.h | 34 +- .../SplineSelectionManipulator.cpp | 45 +- .../Manipulators/SplineSelectionManipulator.h | 57 +- .../Manipulators/SurfaceManipulator.cpp | 84 +- .../Manipulators/SurfaceManipulator.h | 89 +- .../Manipulators/TranslationManipulators.cpp | 103 +- .../Manipulators/TranslationManipulators.h | 75 +- .../AzToolsFramework/Picking/BoundInterface.h | 87 +- .../Picking/ContextBoundAPI.h | 64 +- .../Manipulators/ManipulatorBoundManager.cpp | 41 +- .../Manipulators/ManipulatorBoundManager.h | 38 +- .../Manipulators/ManipulatorBounds.cpp | 64 +- .../Picking/Manipulators/ManipulatorBounds.h | 125 +- .../Viewport/EditorContextMenu.cpp | 41 +- .../Viewport/EditorContextMenu.h | 30 +- .../Viewport/VertexContainerDisplay.cpp | 39 +- .../Viewport/VertexContainerDisplay.h | 29 +- .../Viewport/ViewportMessages.h | 222 +-- .../Viewport/ViewportTypes.cpp | 62 +- .../AzToolsFramework/Viewport/ViewportTypes.h | 252 ++- .../EditorDefaultSelection.cpp | 163 +- .../EditorDefaultSelection.h | 93 +- .../ViewportSelection/EditorHelpers.cpp | 97 +- .../ViewportSelection/EditorHelpers.h | 54 +- .../EditorInteractionSystemComponent.cpp | 44 +- .../EditorInteractionSystemComponent.h | 50 +- ...ractionSystemViewportSelectionRequestBus.h | 60 +- .../EditorPickEntitySelection.cpp | 52 +- .../EditorPickEntitySelection.h | 40 +- .../ViewportSelection/EditorSelectionUtil.cpp | 96 +- .../ViewportSelection/EditorSelectionUtil.h | 65 +- .../EditorTransformComponentSelection.cpp | 1649 ++++++++--------- ...rTransformComponentSelectionRequestBus.cpp | 104 +- ...torTransformComponentSelectionRequestBus.h | 80 +- .../EditorVisibleEntityDataCache.cpp | 100 +- .../EditorVisibleEntityDataCache.h | 31 +- .../Tests/ComponentModeTests.cpp | 131 +- 83 files changed, 4455 insertions(+), 4509 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/std/math.h b/Code/Framework/AzCore/AzCore/std/math.h index 9e9be7944a..f5e2ac7ea7 100644 --- a/Code/Framework/AzCore/AzCore/std/math.h +++ b/Code/Framework/AzCore/AzCore/std/math.h @@ -21,11 +21,14 @@ namespace AZStd using std::asin; using std::atan; using std::atan2; + using std::ceil; using std::cos; using std::exp2; + using std::floor; using std::fmod; using std::round; using std::sin; using std::sqrt; using std::tan; + using std::trunc; } // namespace AZStd diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index 559f7ce460..674e10812b 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -22,7 +22,11 @@ namespace AzFramework { AZ_CVAR( - float, ed_cameraSystemDefaultPlaneHeight, 34.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + ed_cameraSystemDefaultPlaneHeight, + 34.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The default height of the ground plane to do intersection tests against when orbiting"); AZ_CVAR(float, ed_cameraSystemBoostMultiplier, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR(float, ed_cameraSystemTranslateSpeed, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, ""); @@ -41,7 +45,11 @@ namespace AzFramework AZ_CVAR( AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR( - AZ::CVarFixedString, ed_cameraSystemTranslateBackwardKey, "keyboard_key_alphanumeric_S", nullptr, AZ::ConsoleFunctorFlags::Null, + AZ::CVarFixedString, + ed_cameraSystemTranslateBackwardKey, + "keyboard_key_alphanumeric_S", + nullptr, + AZ::ConsoleFunctorFlags::Null, ""); AZ_CVAR( AZ::CVarFixedString, ed_cameraSystemTranslateLeftKey, "keyboard_key_alphanumeric_A", nullptr, AZ::ConsoleFunctorFlags::Null, ""); @@ -326,7 +334,9 @@ namespace AzFramework } Camera RotateCameraInput::StepCamera( - const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, + const Camera& targetCamera, + const ScreenVector& cursorDelta, + [[maybe_unused]] const float scrollDelta, [[maybe_unused]] const float deltaTime) { Camera nextCamera = targetCamera; @@ -374,7 +384,9 @@ namespace AzFramework } Camera PanCameraInput::StepCamera( - const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, + const Camera& targetCamera, + const ScreenVector& cursorDelta, + [[maybe_unused]] const float scrollDelta, [[maybe_unused]] const float deltaTime) { Camera nextCamera = targetCamera; @@ -473,7 +485,9 @@ namespace AzFramework } Camera TranslateCameraInput::StepCamera( - const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, + const Camera& targetCamera, + [[maybe_unused]] const ScreenVector& cursorDelta, + [[maybe_unused]] const float scrollDelta, const float deltaTime) { Camera nextCamera = targetCamera; @@ -630,7 +644,9 @@ namespace AzFramework } Camera OrbitDollyScrollCameraInput::StepCamera( - const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, + const Camera& targetCamera, + [[maybe_unused]] const ScreenVector& cursorDelta, + const float scrollDelta, [[maybe_unused]] const float deltaTime) { Camera nextCamera = targetCamera; @@ -666,7 +682,9 @@ namespace AzFramework } Camera OrbitDollyCursorMoveCameraInput::StepCamera( - const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta, + const Camera& targetCamera, + const ScreenVector& cursorDelta, + [[maybe_unused]] const float scrollDelta, [[maybe_unused]] const float deltaTime) { Camera nextCamera = targetCamera; @@ -686,7 +704,9 @@ namespace AzFramework } Camera ScrollTranslationCameraInput::StepCamera( - const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta, + const Camera& targetCamera, + [[maybe_unused]] const ScreenVector& cursorDelta, + const float scrollDelta, [[maybe_unused]] const float deltaTime) { Camera nextCamera = targetCamera; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h index c9211e9f26..1eba4f3799 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ActionDispatcher.h @@ -97,7 +97,7 @@ namespace AzManipulatorTestFramework if (m_logging) { AZStd::string message = AZStd::string::format(format, args...); - std::cout << "[ActionDispatcher] " << message.c_str() << "\n"; + AZ_Printf("[ActionDispatcher] %s", message.c_str()); } } diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h index f1c32e4d8d..9d380003e2 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h @@ -21,12 +21,14 @@ namespace AzManipulatorTestFramework { //! Create a linear manipulator with a unit sphere bound. AZStd::shared_ptr CreateLinearManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, + const AZ::Vector3& position = AZ::Vector3::CreateZero(), float radius = 1.0f); //! Create a planar manipulator with a unit sphere bound. AZStd::shared_ptr CreatePlanarManipulator( - const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(), + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, + const AZ::Vector3& position = AZ::Vector3::CreateZero(), float radius = 1.0f); //! Create a mouse pick from the specified ray and screen point. @@ -39,7 +41,8 @@ namespace AzManipulatorTestFramework //! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers. AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction( - const AzToolsFramework::ViewportInteraction::MousePick& mousePick, AzToolsFramework::ViewportInteraction::MouseButtons buttons, + const AzToolsFramework::ViewportInteraction::MousePick& mousePick, + AzToolsFramework::ViewportInteraction::MouseButtons buttons, AzToolsFramework::ViewportInteraction::InteractionId interactionId, AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers); diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h index 6759c2255f..1faf4eff65 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h @@ -12,14 +12,13 @@ #pragma once -#include #include +#include namespace AzManipulatorTestFramework { //! Dispatches actions immediately to the manipulators. - class ImmediateModeActionDispatcher - : public ActionDispatcher + class ImmediateModeActionDispatcher : public ActionDispatcher { using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier; using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers; @@ -62,7 +61,7 @@ namespace AzManipulatorTestFramework void MouseLButtonUpImpl() override; void MousePositionImpl(const AzFramework::ScreenPoint& position) override; void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override; - void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override; + void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override; void ExpectManipulatorBeingInteractedImpl() override; void ExpectManipulatorNotBeingInteractedImpl() override; void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override; @@ -97,8 +96,7 @@ namespace AzManipulatorTestFramework return this; } - inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers( - KeyboardModifiers& keyboardModifiers) + inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers(KeyboardModifiers& keyboardModifiers) { keyboardModifiers = GetKeyboardModifiers(); return this; diff --git a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp index 985c21cf8e..83746c9490 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/AzManipulatorTestFrameworkUtils.cpp @@ -30,8 +30,10 @@ namespace AzManipulatorTestFramework // create a default sphere view for a manipulator for simple intersection template void SetupManipulatorView( - AZStd::shared_ptr manipulator, const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, - const AZ::Vector3& position, const float radius) + AZStd::shared_ptr manipulator, + const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, + const AZ::Vector3& position, + const float radius) { // unit sphere view auto sphereView = AzToolsFramework::CreateManipulatorViewSphere( diff --git a/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp index 5c5f77629c..192202cee2 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/DirectManipulatorViewportInteraction.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include #include @@ -19,10 +19,10 @@ namespace AzManipulatorTestFramework using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction; using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent; - class CustomManipulatorManager - : public AzToolsFramework::ManipulatorManager + class CustomManipulatorManager : public AzToolsFramework::ManipulatorManager { using ManagerBase = AzToolsFramework::ManipulatorManager; + public: using ManagerBase::ManagerBase; @@ -31,18 +31,17 @@ namespace AzManipulatorTestFramework }; //! Implementation of the manipulator interface using direct access to the manipulator manager. - class DirectCallManipulatorManager - : public ManipulatorManagerInterface + class DirectCallManipulatorManager : public ManipulatorManagerInterface { public: DirectCallManipulatorManager( - ViewportInteractionInterface* viewportInteraction, - AZStd::shared_ptr manipulatorManager); - + ViewportInteractionInterface* viewportInteraction, AZStd::shared_ptr manipulatorManager); + // ManipulatorManagerInterface ... void ConsumeMouseInteractionEvent(const MouseInteractionEvent& event); AzToolsFramework::ManipulatorManagerId GetId() const override; bool ManipulatorBeingInteracted() const override; + private: // Trigger the updating of manipulator bounds. void DrawManipulators(const MouseInteraction& mouseInteraction); @@ -61,8 +60,7 @@ namespace AzManipulatorTestFramework } DirectCallManipulatorManager::DirectCallManipulatorManager( - ViewportInteractionInterface* viewportInteraction, - AZStd::shared_ptr manipulatorManager) + ViewportInteractionInterface* viewportInteraction, AZStd::shared_ptr manipulatorManager) : m_viewportInteraction(viewportInteraction) , m_manipulatorManager(AZStd::move(manipulatorManager)) { @@ -126,11 +124,9 @@ namespace AzManipulatorTestFramework DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction() : m_customManager( - AZStd::make_unique( - AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId")))) + AZStd::make_unique(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId")))) , m_viewportInteraction(AZStd::make_unique()) - , m_manipulatorManager( - AZStd::make_unique(m_viewportInteraction.get(), m_customManager)) + , m_manipulatorManager(AZStd::make_unique(m_viewportInteraction.get(), m_customManager)) { } diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp index ad59d9578a..356a146125 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ImmediateModeActionDispatcher.cpp @@ -10,8 +10,8 @@ * */ -#include #include +#include #include #include @@ -33,8 +33,7 @@ namespace AzManipulatorTestFramework using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier; using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent; - ImmediateModeActionDispatcher::ImmediateModeActionDispatcher( - ManipulatorViewportInteraction& viewportManipulatorInteraction) + ImmediateModeActionDispatcher::ImmediateModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction) : m_viewportManipulatorInteraction(viewportManipulatorInteraction) { } @@ -126,8 +125,7 @@ namespace AzManipulatorTestFramework void ImmediateModeActionDispatcher::EnterComponentModeImpl(const AZ::Uuid& uuid) { using AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus; - ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType, uuid); + ComponentModeSystemRequestBus::Broadcast(&ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType, uuid); } const AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent() const @@ -144,8 +142,7 @@ namespace AzManipulatorTestFramework AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent() { - return const_cast( - static_cast(this)->GetMouseInteractionEvent()); + return const_cast(static_cast(this)->GetMouseInteractionEvent()); } ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectTrue(bool result) @@ -162,8 +159,7 @@ namespace AzManipulatorTestFramework return this; } - ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetEntityWorldTransform( - AZ::EntityId entityId, AZ::Transform& transform) + ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetEntityWorldTransform(AZ::EntityId entityId, AZ::Transform& transform) { Log("Getting entity world transform"); transform = AzToolsFramework::GetWorldTransform(entityId); diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp index 8cc906f339..b2da9965e6 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/BusCallTest.cpp @@ -11,17 +11,18 @@ */ #include "AzManipulatorTestFrameworkTestFixtures.h" -#include #include +#include namespace UnitTest { - class AzManipulatorTestFrameworkBusCallTestFixture - : public LinearManipulatorTestFixture + class AzManipulatorTestFrameworkBusCallTestFixture : public LinearManipulatorTestFixture { protected: AzManipulatorTestFrameworkBusCallTestFixture() - : LinearManipulatorTestFixture(AzToolsFramework::g_mainManipulatorManagerId) {} + : LinearManipulatorTestFixture(AzToolsFramework::g_mainManipulatorManagerId) + { + } bool IsManipulatorInteractingBusCall() const { @@ -37,8 +38,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportLeftMouseClick) { // given a left mouse down ray in world space - auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent( - m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = + AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down and up events AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -56,8 +57,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveHover) { // given a left mouse down ray in world space - const auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent( - m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move); + const auto event = + AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move); // consume the mouse move event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -75,8 +76,8 @@ namespace UnitTest TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveActive) { // given a left mouse down ray in world space - auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent( - m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = + AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -110,14 +111,14 @@ namespace UnitTest const AZ::Vector3 initialManipulatorPosition = m_linearManipulator->GetLocalPosition(); m_linearManipulator->InstallMouseMoveCallback( [&movementAlongAxis, this](const AzToolsFramework::LinearManipulator::Action& action) - { - movementAlongAxis = action.LocalPositionOffset(); - m_linearManipulator->SetLocalPosition(action.LocalPosition()); - }); + { + movementAlongAxis = action.LocalPositionOffset(); + m_linearManipulator->SetLocalPosition(action.LocalPosition()); + }); // given a left mouse down ray in world space - auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent( - m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); + auto event = + AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down); // consume the mouse down event AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); @@ -134,7 +135,7 @@ namespace UnitTest // consume the mouse up event event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up; AzManipulatorTestFramework::DispatchMouseInteractionEvent(event); - + // expect the left mouse down/up sanity flags to be set EXPECT_TRUE(m_receivedLeftMouseDown); EXPECT_TRUE(m_receivedLeftMouseUp); diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/DirectCallTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/DirectCallTest.cpp index bec61ce9a8..af810c1dcf 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/DirectCallTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/DirectCallTest.cpp @@ -14,10 +14,10 @@ namespace UnitTest { - class CustomManipulatorManager - : public AzToolsFramework::ManipulatorManager + class CustomManipulatorManager : public AzToolsFramework::ManipulatorManager { using ManagerBase = AzToolsFramework::ManipulatorManager; + public: using ManagerBase::ManagerBase; @@ -27,17 +27,17 @@ namespace UnitTest } }; - class AzManipulatorTestFrameworkCustomManagerTestFixture - : public LinearManipulatorTestFixture + class AzManipulatorTestFrameworkCustomManagerTestFixture : public LinearManipulatorTestFixture { protected: AzManipulatorTestFrameworkCustomManagerTestFixture() - : LinearManipulatorTestFixture(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))) {} + : LinearManipulatorTestFixture(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))) + { + } void SetUpEditorFixtureImpl() override { - m_manipulatorManager = - AZStd::make_shared(m_manipulatorManagerId); + m_manipulatorManager = AZStd::make_shared(m_manipulatorManagerId); LinearManipulatorTestFixture::SetUpEditorFixtureImpl(); } @@ -115,9 +115,9 @@ namespace UnitTest m_linearManipulator->InstallMouseMoveCallback( [&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action) - { - movementAlongAxis = action.m_current.m_localPositionOffset; - }); + { + movementAlongAxis = action.m_current.m_localPositionOffset; + }); // consume the mouse down event m_manipulatorManager->ConsumeViewportMousePress(m_interaction); @@ -141,4 +141,3 @@ namespace UnitTest EXPECT_EQ(movementAlongAxis, expectedPositionAfterMovementAlongAxis); } } // namespace UnitTest - diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp index d6006ba74f..160a9933d9 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/GridSnappingTest.cpp @@ -12,6 +12,7 @@ #include "AzManipulatorTestFrameworkTestFixtures.h" +#include #include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include namespace UnitTest { @@ -94,7 +94,8 @@ namespace UnitTest template void ValidateManipulatorSnappingBehavior( - AZStd::shared_ptr manipulator, AzManipulatorTestFramework::ImmediateModeActionDispatcher* actionDispatcher, + AZStd::shared_ptr manipulator, + AzManipulatorTestFramework::ImmediateModeActionDispatcher* actionDispatcher, const AzFramework::CameraState& cameraState) { manipulator->SetLocalOrientation(AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(180.0f, 0.0f, 135.0f))); diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp index 6ba44cc71b..4aad2ea138 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/ViewportInteractionTest.cpp @@ -15,8 +15,7 @@ namespace UnitTest { - class AValidViewportInteraction - : public ToolsApplicationFixture + class AValidViewportInteraction : public ToolsApplicationFixture { public: AValidViewportInteraction() @@ -27,8 +26,7 @@ namespace UnitTest protected: void SetUpEditorFixtureImpl() override { - m_cameraState = - AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f)); + m_cameraState = AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f)); } public: diff --git a/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp b/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp index a6c58971f6..6168e9cece 100644 --- a/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Tests/WorldSpaceBuilderTest.cpp @@ -11,49 +11,48 @@ */ #include -#include #include +#include #include -#include #include -#include +#include #include +#include namespace UnitTest { - class AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture - : public ToolsApplicationFixture + class AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture : public ToolsApplicationFixture { protected: struct State { State(AZStd::unique_ptr viewportManipulatorInteraction) : m_viewportManipulatorInteraction(viewportManipulatorInteraction.release()) - , m_actionDispatcher(AZStd::make_unique(*m_viewportManipulatorInteraction)) - , m_linearManipulator( - AzManipulatorTestFramework::CreateLinearManipulator( - m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), - /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), - /*radius=*/m_boundsRadius)) + , m_actionDispatcher( + AZStd::make_unique(*m_viewportManipulatorInteraction)) + , m_linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator( + m_viewportManipulatorInteraction->GetManipulatorManager().GetId(), + /*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f), + /*radius=*/m_boundsRadius)) { // default sanity check call backs m_linearManipulator->InstallLeftMouseDownCallback( [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) - { - m_receivedLeftMouseDown = true; - }); + { + m_receivedLeftMouseDown = true; + }); m_linearManipulator->InstallMouseMoveCallback( [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) - { - m_receivedMouseMove = true; - }); + { + m_receivedMouseMove = true; + }); m_linearManipulator->InstallLeftMouseUpCallback( [this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action) - { - m_receivedLeftMouseUp = true; - }); + { + m_receivedLeftMouseUp = true; + }); } ~State() = default; @@ -79,13 +78,12 @@ namespace UnitTest protected: void SetUpEditorFixtureImpl() override { - m_directState = AZStd::make_unique( - AZStd::make_unique()); - m_busState = AZStd::make_unique( - AZStd::make_unique()); + m_directState = + AZStd::make_unique(AZStd::make_unique()); + m_busState = + AZStd::make_unique(AZStd::make_unique()); m_cameraState = - AzFramework::CreateIdentityDefaultCamera( - AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); + AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize); } void TearDownEditorFixtureImpl() override @@ -105,8 +103,7 @@ namespace UnitTest { // given a left mouse down ray in world space // consume the mouse down and up events - state.m_actionDispatcher - ->CameraState(m_cameraState) + state.m_actionDispatcher->CameraState(m_cameraState) ->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState)) ->MouseLButtonDown() ->Trace("Expecting left mouse button down") @@ -126,31 +123,27 @@ namespace UnitTest ->ExpectTrue(state.m_receivedLeftMouseUp) ->ExpectTrue(state.m_receivedMouseMove) ->ExpectFalse(state.m_linearManipulator->PerformingAction()) - ->ExpectManipulatorNotBeingInteracted() - ; + ->ExpectManipulatorNotBeingInteracted(); } void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveHover(State& state) { // given a left mouse down ray in world space // consume the mouse move event - state.m_actionDispatcher - ->CameraState(m_cameraState) + state.m_actionDispatcher->CameraState(m_cameraState) ->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState)) ->ExpectFalse(state.m_linearManipulator->PerformingAction()) ->ExpectManipulatorNotBeingInteracted() ->ExpectFalse(state.m_receivedLeftMouseDown) ->ExpectFalse(state.m_receivedMouseMove) - ->ExpectFalse(state.m_receivedLeftMouseUp) - ; + ->ExpectFalse(state.m_receivedLeftMouseUp); } void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveActive(State& state) { // given a left mouse down ray in world space // consume the mouse move event - state.m_actionDispatcher - ->CameraState(m_cameraState) + state.m_actionDispatcher->CameraState(m_cameraState) ->MouseLButtonDown() ->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState)) ->ExpectTrue(state.m_linearManipulator->PerformingAction()) @@ -158,8 +151,7 @@ namespace UnitTest ->MouseLButtonUp() ->ExpectTrue(state.m_receivedLeftMouseDown) ->ExpectTrue(state.m_receivedMouseMove) - ->ExpectTrue(state.m_receivedLeftMouseUp) - ; + ->ExpectTrue(state.m_receivedLeftMouseUp); } void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::MoveManipulatorAlongAxis(State& state) @@ -176,8 +168,7 @@ namespace UnitTest // adjusted final world position taking into account the manipulator position relative to the camera const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound); // calculate the position in screen space of the initial position of the manipulator - const auto initialPositionScreen = - AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); + const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, m_cameraState); // calculate the position in screen space of the final position of the manipulator const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState); @@ -185,12 +176,11 @@ namespace UnitTest state.m_linearManipulator->InstallMouseMoveCallback( [&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action) - { - movementAlongAxis = action.LocalPosition(); - }); + { + movementAlongAxis = action.LocalPosition(); + }); - state.m_actionDispatcher - ->CameraState(m_cameraState) + state.m_actionDispatcher->CameraState(m_cameraState) ->MousePosition(initialPositionScreen) ->MouseLButtonDown() ->ExpectTrue(state.m_linearManipulator->PerformingAction()) @@ -199,8 +189,7 @@ namespace UnitTest ->MouseLButtonUp() ->ExpectTrue(state.m_receivedLeftMouseDown) ->ExpectTrue(state.m_receivedLeftMouseUp) - ->ExpectTrue(movementAlongAxis.IsClose(finalPositionWorld, 0.01f)) - ; + ->ExpectTrue(movementAlongAxis.IsClose(finalPositionWorld, 0.01f)); } TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, ConsumeViewportLeftMouseClick) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp index 9a4a952d8f..6141fd9642 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.cpp @@ -1,28 +1,32 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "AngularManipulator.h" #include -#include #include +#include namespace AzToolsFramework { - static const float s_circularRotateThresholdDegrees = 80.0f; + static const float CircularRotateThresholdDegrees = 80.0f; AngularManipulator::ActionInternal AngularManipulator::CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform, - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, const float rayDistance) + const Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Transform& localTransform, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const float rayDistance) { const AZ::Transform worldFromLocalWithTransform = worldFromLocal * localTransform; const AZ::Vector3 worldAxis = TransformDirectionNoScaling(worldFromLocalWithTransform, fixed.m_axis); @@ -35,7 +39,7 @@ namespace AzToolsFramework // if angular manipulator axis is at right angles to us, use initial ray direction // as plane normal and use hit position on manipulator as plane point const float pickAngle = AZ::RadToDeg(AZ::Acos(AZ::Abs(rayDirection.Dot(worldAxis)))); - if (pickAngle > s_circularRotateThresholdDegrees) + if (pickAngle > CircularRotateThresholdDegrees) { actionInternal.m_start.m_planeNormal = -rayDirection; actionInternal.m_start.m_planePoint = rayOrigin + rayDirection * rayDistance; @@ -43,8 +47,8 @@ namespace AzToolsFramework // store initial world hit position Internal::CalculateRayPlaneIntersectingPoint( - rayOrigin, rayDirection, actionInternal.m_start.m_planePoint, - actionInternal.m_start.m_planeNormal, actionInternal.m_current.m_worldHitPosition); + rayOrigin, rayDirection, actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal, + actionInternal.m_current.m_worldHitPosition); // store entity transform (to go from local to world space) // and store our own starting local transform @@ -56,31 +60,33 @@ namespace AzToolsFramework } AngularManipulator::Action AngularManipulator::CalculateManipulationDataAction( - const Fixed& fixed, ActionInternal& actionInternal, const AZ::Transform& worldFromLocal, - const AZ::Transform& localTransform, const bool snapping, const float angleStepDegrees, - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, + const Fixed& fixed, + ActionInternal& actionInternal, + const AZ::Transform& worldFromLocal, + const AZ::Transform& localTransform, + const bool snapping, + const float angleStepDegrees, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, const ViewportInteraction::KeyboardModifiers keyboardModifiers) { const AZ::Transform worldFromLocalWithTransform = worldFromLocal * localTransform; const AZ::Vector3 worldAxis = TransformDirectionNoScaling(worldFromLocalWithTransform, fixed.m_axis); AZ::Vector3 worldHitPosition = AZ::Vector3::CreateZero(); - Internal::CalculateRayPlaneIntersectingPoint(rayOrigin, rayDirection, - actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal, - worldHitPosition); + Internal::CalculateRayPlaneIntersectingPoint( + rayOrigin, rayDirection, actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal, worldHitPosition); // get vector from center of rotation for current and previous frame const AZ::Vector3 center = worldFromLocalWithTransform.GetTranslation(); const AZ::Vector3 currentWorldHitVector = (worldHitPosition - center).GetNormalizedSafe(); - const AZ::Vector3 previousWorldHitVector = - (actionInternal.m_current.m_worldHitPosition - center).GetNormalizedSafe(); + const AZ::Vector3 previousWorldHitVector = (actionInternal.m_current.m_worldHitPosition - center).GetNormalizedSafe(); // calculate which direction we rotated const AZ::Vector3 worldAxisRight = worldAxis.Cross(previousWorldHitVector); const float rotateSign = Sign(currentWorldHitVector.Dot(worldAxisRight)); // how far did we rotate this frame - const float rotationAngleRad = AZ::Acos(AZ::GetMin( - 1.0f, currentWorldHitVector.Dot(previousWorldHitVector))); + const float rotationAngleRad = AZ::Acos(AZ::GetMin(1.0f, currentWorldHitVector.Dot(previousWorldHitVector))); actionInternal.m_current.m_worldHitPosition = worldHitPosition; // if we're snapping, only increment current radians when we know @@ -148,16 +154,13 @@ namespace AzToolsFramework // calculate initial state when mouse press first happens m_actionInternal = CalculateManipulationDataStart( m_fixed, TransformNormalizedScale(GetSpace()), TransformNormalizedScale(GetLocalTransform()), - interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, - rayIntersectionDistance); + interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, rayIntersectionDistance); if (m_onLeftMouseDownCallback) { m_onLeftMouseDownCallback(CalculateManipulationDataAction( - m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, - m_actionInternal.m_start.m_localTransform, snapping, angleStep, - interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, - interaction.m_keyboardModifiers)); + m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform, snapping, + angleStep, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers)); } } @@ -167,12 +170,9 @@ namespace AzToolsFramework { // calculate delta rotation m_onMouseMoveCallback(CalculateManipulationDataAction( - m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, - m_actionInternal.m_start.m_localTransform, - AngleSnapping(interaction.m_interactionId.m_viewportId), - AngleStep(interaction.m_interactionId.m_viewportId), - interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, - interaction.m_keyboardModifiers)); + m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform, + AngleSnapping(interaction.m_interactionId.m_viewportId), AngleStep(interaction.m_interactionId.m_viewportId), + interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers)); } } @@ -181,12 +181,9 @@ namespace AzToolsFramework if (m_onLeftMouseUpCallback) { m_onLeftMouseUpCallback(CalculateManipulationDataAction( - m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, - m_actionInternal.m_start.m_localTransform, - AngleSnapping(interaction.m_interactionId.m_viewportId), - AngleStep(interaction.m_interactionId.m_viewportId), - interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, - interaction.m_keyboardModifiers)); + m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform, + AngleSnapping(interaction.m_interactionId.m_viewportId), AngleStep(interaction.m_interactionId.m_viewportId), + interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers)); } } @@ -197,12 +194,9 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& mouseInteraction) { m_manipulatorView->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - ApplySpace(GetLocalTransform()), GetNonUniformScale(), - AZ::Vector3::CreateZero(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState, + mouseInteraction); } void AngularManipulator::SetAxis(const AZ::Vector3& axis) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.h index e2f95fce5e..8e0468aa90 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/AngularManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,14 +22,14 @@ namespace AzToolsFramework { class ManipulatorView; - /// AngularManipulator serves as a visual tool for users to change a component's property based on rotation - /// around an axis. The rotation angle increases if the rotation goes counter clock-wise when looking - /// in the opposite direction the rotation axis points to. + //! AngularManipulator serves as a visual tool for users to change a component's property based on rotation + //! around an axis. The rotation angle increases if the rotation goes counter clock-wise when looking + //! in the opposite direction the rotation axis points to. class AngularManipulator : public BaseManipulator , public ManipulatorSpaceWithLocalTransform { - /// Private constructor. + //! Private constructor. explicit AngularManipulator(const AZ::Transform& worldFromLocal); public: @@ -42,33 +42,36 @@ namespace AzToolsFramework ~AngularManipulator() = default; - /// A Manipulator must only be created and managed through a shared_ptr. + //! A Manipulator must only be created and managed through a shared_ptr. static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal); - /// The state of the manipulator at the start of an interaction. + //! The state of the manipulator at the start of an interaction. struct Start { - AZ::Quaternion m_space; ///< Starting orientation space of manipulator. - AZ::Quaternion m_rotation; ///< Starting local rotation of the manipulator. + AZ::Quaternion m_space; //!< Starting orientation space of manipulator. + AZ::Quaternion m_rotation; //!< Starting local rotation of the manipulator. }; - /// The state of the manipulator during an interaction. + //! The state of the manipulator during an interaction. struct Current { - AZ::Quaternion m_delta; ///< Amount of rotation to apply to manipulator during action. + AZ::Quaternion m_delta; //!< Amount of rotation to apply to manipulator during action. }; - /// Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). + //! Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). struct Action { Start m_start; Current m_current; ViewportInteraction::KeyboardModifiers m_modifiers; - AZ::Quaternion LocalOrientation() const { return m_start.m_rotation * m_current.m_delta; } + AZ::Quaternion LocalOrientation() const + { + return m_start.m_rotation * m_current.m_delta; + } }; - /// This is the function signature of callbacks that will be invoked whenever a manipulator - /// is clicked on or dragged. + //! This is the function signature of callbacks that will be invoked whenever a manipulator + //! is clicked on or dragged. using MouseActionCallback = AZStd::function; void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback); @@ -82,46 +85,49 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& mouseInteraction) override; void SetAxis(const AZ::Vector3& axis); - const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; } + const AZ::Vector3& GetAxis() const + { + return m_fixed.m_axis; + } void SetView(AZStd::unique_ptr&& view); - ManipulatorView* GetView() const { return m_manipulatorView.get(); } + ManipulatorView* GetView() const + { + return m_manipulatorView.get(); + } private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; - void OnMouseMoveImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; + void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override; void SetBoundsDirtyImpl() override; void InvalidateImpl() override; - /// Unchanging data set once for the angular manipulator. + //! Unchanging data set once for the angular manipulator. struct Fixed { - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); ///< Axis for this angular manipulator to rotate around. + AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); //!< Axis for this angular manipulator to rotate around. }; - /// Initial data recorded when a press first happens with an angular manipulator. + //! Initial data recorded when a press first happens with an angular manipulator. struct StartInternal { - AZ::Transform m_worldFromLocal; ///< Initial transform when pressed. - AZ::Transform m_localTransform; ///< Additional transform (offset) to apply to manipulator. - AZ::Vector3 m_planePoint; ///< Position on plane to use for ray intersection. - AZ::Vector3 m_planeNormal; ///< Normal of plane to use for ray intersection. + AZ::Transform m_worldFromLocal; //!< Initial transform when pressed. + AZ::Transform m_localTransform; //!< Additional transform (offset) to apply to manipulator. + AZ::Vector3 m_planePoint; //!< Position on plane to use for ray intersection. + AZ::Vector3 m_planeNormal; //!< Normal of plane to use for ray intersection. }; - /// Current data recorded each frame during an interaction with an angular manipulator. + //! Current data recorded each frame during an interaction with an angular manipulator. struct CurrentInternal { - float m_preSnapRadians = 0.0f; ///< Amount of rotation before a snap (snap increment accumulator). - float m_radians = 0.0f; ///< Amount of rotation about the axis for this action. - AZ::Vector3 m_worldHitPosition; ///< Initial world space hit position. + float m_preSnapRadians = 0.0f; //!< Amount of rotation before a snap (snap increment accumulator). + float m_radians = 0.0f; //!< Amount of rotation about the axis for this action. + AZ::Vector3 m_worldHitPosition; //!< Initial world space hit position. }; - /// Wrap start and current internal data during an interaction with an angular manipulator. + //! Wrap start and current internal data during an interaction with an angular manipulator. struct ActionInternal { StartInternal m_start; @@ -135,16 +141,25 @@ namespace AzToolsFramework MouseActionCallback m_onLeftMouseUpCallback = nullptr; MouseActionCallback m_onMouseMoveCallback = nullptr; - AZStd::unique_ptr m_manipulatorView; ///< Look of manipulator. + AZStd::unique_ptr m_manipulatorView; //!< Look of manipulator. static ActionInternal CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform, - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float rayDistance); + const Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Transform& localTransform, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + float rayDistance); static Action CalculateManipulationDataAction( - const Fixed& fixed, ActionInternal& actionInternal, const AZ::Transform& worldFromLocal, - const AZ::Transform& localTransform, bool snapping, float angleStepDegrees, - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, + const Fixed& fixed, + ActionInternal& actionInternal, + const AZ::Transform& worldFromLocal, + const AZ::Transform& localTransform, + bool snapping, + float angleStepDegrees, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, ViewportInteraction::KeyboardModifiers keyboardModifiers); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp index 955d10d3bd..73d0dc72be 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.cpp @@ -1,33 +1,30 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "BaseManipulator.h" #include -#include #include +#include namespace AzToolsFramework { - AZ_CVAR( - bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, - "Enable debug drawing for Manipulators"); + AZ_CVAR(bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators"); const AZ::Color BaseManipulator::s_defaultMouseOverColor = AZ::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow AZ_CLASS_ALLOCATOR_IMPL(BaseManipulator, AZ::SystemAllocator, 0) - static bool EntityIdAndEntityComponentIdComparison( - const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId) + static bool EntityIdAndEntityComponentIdComparison(const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId) { return entityId == entityComponentId.GetEntityId(); } @@ -38,8 +35,7 @@ namespace AzToolsFramework EndUndoBatch(); } - bool BaseManipulator::OnLeftMouseDown( - const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) + bool BaseManipulator::OnLeftMouseDown(const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -57,8 +53,7 @@ namespace AzToolsFramework (*this.*m_onLeftMouseDownImpl)(interaction, rayIntersectionDistance); - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); return true; } @@ -66,8 +61,7 @@ namespace AzToolsFramework return false; } - bool BaseManipulator::OnRightMouseDown( - const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) + bool BaseManipulator::OnRightMouseDown(const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -85,8 +79,7 @@ namespace AzToolsFramework (*this.*m_onRightMouseDownImpl)(interaction, rayIntersectionDistance); - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); return true; } @@ -118,8 +111,7 @@ namespace AzToolsFramework EndUndoBatch(); } - bool BaseManipulator::OnMouseOver( - const ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction) + bool BaseManipulator::OnMouseOver(const ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -132,8 +124,7 @@ namespace AzToolsFramework { OnMouseWheelImpl(interaction); - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); } void BaseManipulator::OnMouseMove(const ViewportInteraction::MouseInteraction& interaction) @@ -142,16 +133,13 @@ namespace AzToolsFramework if (!m_performingAction) { - AZ_Warning( - "Manipulators", false, - "MouseMove action received, but this manipulator is not performing an action"); + AZ_Warning("Manipulators", false, "MouseMove action received, but this manipulator is not performing an action"); return; } // ensure property grid (entity inspector) values are refreshed - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); OnMouseMoveImpl(interaction); } @@ -170,16 +158,14 @@ namespace AzToolsFramework Unregister(); } - ManipulatorManagerRequestBus::Event(managerId, - &ManipulatorManagerRequestBus::Events::RegisterManipulator, shared_from_this()); + ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::RegisterManipulator, shared_from_this()); } void BaseManipulator::Unregister() { // if the manipulator has already been unregistered, the m_manipulatorManagerId // should be invalid which makes the call below a no-op. - ManipulatorManagerRequestBus::Event(m_manipulatorManagerId, - &ManipulatorManagerRequestBus::Events::UnregisterManipulator, this); + ManipulatorManagerRequestBus::Event(m_manipulatorManagerId, &ManipulatorManagerRequestBus::Events::UnregisterManipulator, this); } void BaseManipulator::Invalidate() @@ -197,8 +183,7 @@ namespace AzToolsFramework if (m_performingAction) { AZ_Warning( - "Manipulators", false, - "MouseDown action received, but the manipulator (id: %d) is still performing an action", + "Manipulators", false, "MouseDown action received, but the manipulator (id: %d) is still performing an action", GetManipulatorId()); return; @@ -214,8 +199,7 @@ namespace AzToolsFramework if (!m_performingAction) { AZ_Warning( - "Manipulators", false, - "MouseUp action received, but this manipulator (id: %d) didn't receive MouseDown action before", + "Manipulators", false, "MouseUp action received, but this manipulator (id: %d) didn't receive MouseDown action before", GetManipulatorId()); return; } @@ -263,13 +247,13 @@ namespace AzToolsFramework if (entityComponentIdPair.GetComponentId() != AZ::InvalidComponentId) { PropertyEditorEntityChangeNotificationBus::Event( - entityComponentIdPair.GetEntityId(), - &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, + entityComponentIdPair.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, entityComponentIdPair.GetComponentId()); } else { - AZ_Warning("Manipulators", false, + AZ_Warning( + "Manipulators", false, "This Manipulator was only registered with an EntityId and not an EntityComponentIdPair. " "Please use AddEntityComponentIdPair() instead of AddEntityId() when registering what this " "Manipulator is changing."); @@ -280,8 +264,7 @@ namespace AzToolsFramework for (const AZ::Component* component : entity->GetComponents()) { PropertyEditorEntityChangeNotificationBus::Event( - entity->GetId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, - component->GetId()); + entity->GetId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, component->GetId()); } } } @@ -298,9 +281,7 @@ namespace AzToolsFramework { // look for a match (keep looking in case we have several entity ids with different component ids) const auto entityComponentPairId = - m_entityComponentIdPairs.find_as( - entityId, AZStd::hash(), - &EntityIdAndEntityComponentIdComparison); + m_entityComponentIdPairs.find_as(entityId, AZStd::hash(), &EntityIdAndEntityComponentIdComparison); // update the afterErased variable so we can return an iterator // to the correct position in the container. @@ -334,9 +315,8 @@ namespace AzToolsFramework bool BaseManipulator::HasEntityId(const AZ::EntityId entityId) const { - return m_entityComponentIdPairs.find_as( - entityId, AZStd::hash(), - &EntityIdAndEntityComponentIdComparison) != m_entityComponentIdPairs.end(); + return m_entityComponentIdPairs.find_as(entityId, AZStd::hash(), &EntityIdAndEntityComponentIdComparison) != + m_entityComponentIdPairs.end(); } bool BaseManipulator::HasEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) const @@ -346,7 +326,8 @@ namespace AzToolsFramework void Manipulators::Register(const ManipulatorManagerId manipulatorManagerId) { - ProcessManipulators([manipulatorManagerId](BaseManipulator* manipulator) + ProcessManipulators( + [manipulatorManagerId](BaseManipulator* manipulator) { manipulator->Register(manipulatorManagerId); }); @@ -354,7 +335,8 @@ namespace AzToolsFramework void Manipulators::Unregister() { - ProcessManipulators([](BaseManipulator* manipulator) + ProcessManipulators( + [](BaseManipulator* manipulator) { if (manipulator->Registered()) { @@ -365,7 +347,8 @@ namespace AzToolsFramework void Manipulators::SetBoundsDirty() { - ProcessManipulators([](BaseManipulator* manipulator) + ProcessManipulators( + [](BaseManipulator* manipulator) { manipulator->SetBoundsDirty(); }); @@ -373,7 +356,8 @@ namespace AzToolsFramework void Manipulators::AddEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) { - ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator) + ProcessManipulators( + [&entityComponentIdPair](BaseManipulator* manipulator) { manipulator->AddEntityComponentIdPair(entityComponentIdPair); }); @@ -381,7 +365,8 @@ namespace AzToolsFramework void Manipulators::RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) { - ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator) + ProcessManipulators( + [&entityComponentIdPair](BaseManipulator* manipulator) { manipulator->RemoveEntityComponentIdPair(entityComponentIdPair); }); @@ -389,7 +374,8 @@ namespace AzToolsFramework void Manipulators::RemoveEntityId(const AZ::EntityId entityId) { - ProcessManipulators([entityId](BaseManipulator* manipulator) + ProcessManipulators( + [entityId](BaseManipulator* manipulator) { manipulator->RemoveEntityId(entityId); }); @@ -398,7 +384,8 @@ namespace AzToolsFramework bool Manipulators::PerformingAction() { bool performingAction = false; - ProcessManipulators([&performingAction](BaseManipulator* manipulator) + ProcessManipulators( + [&performingAction](BaseManipulator* manipulator) { if (manipulator->PerformingAction()) { @@ -412,7 +399,8 @@ namespace AzToolsFramework bool Manipulators::Registered() { bool registered = false; - ProcessManipulators([®istered](BaseManipulator* manipulator) + ProcessManipulators( + [®istered](BaseManipulator* manipulator) { if (manipulator->Registered()) { @@ -470,8 +458,12 @@ namespace AzToolsFramework namespace Internal { - bool CalculateRayPlaneIntersectingPoint(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, - const AZ::Vector3& pointOnPlane, const AZ::Vector3& planeNormal, AZ::Vector3& resultIntersectingPoint) + bool CalculateRayPlaneIntersectingPoint( + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZ::Vector3& pointOnPlane, + const AZ::Vector3& planeNormal, + AZ::Vector3& resultIntersectingPoint) { float t = 0.0f; if (AZ::Intersect::IntersectRayPlane(rayOrigin, rayDirection, pointOnPlane, planeNormal, t) > 0) @@ -484,11 +476,12 @@ namespace AzToolsFramework } AZ::Vector3 TryConstrainHitPositionToView( - const AZ::Vector3& currentLocalHitPosition, const AZ::Vector3& startLocalHitPosition, - const AZ::Transform& localFromWorld, const AzFramework::CameraState& cameraState) + const AZ::Vector3& currentLocalHitPosition, + const AZ::Vector3& startLocalHitPosition, + const AZ::Transform& localFromWorld, + const AzFramework::CameraState& cameraState) { - if (currentLocalHitPosition.GetDistance(localFromWorld.TransformPoint(cameraState.m_position)) - > cameraState.m_farClip) + if (currentLocalHitPosition.GetDistance(localFromWorld.TransformPoint(cameraState.m_position)) > cameraState.m_farClip) { return startLocalHitPosition; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h index 2b078f62b7..04f2bc456b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,13 +22,13 @@ #include #include #include -#include "ManipulatorSpace.h" +#include namespace AzFramework { struct CameraState; class DebugDisplayRequests; -} +} // namespace AzFramework namespace AzToolsFramework { @@ -46,9 +46,8 @@ namespace AzToolsFramework struct ManipulatorManagerState; - /// The base class for manipulators, providing interfaces for users of manipulators to talk to. - class BaseManipulator - : public AZStd::enable_shared_from_this + //! The base class for manipulators, providing interfaces for users of manipulators to talk to. + class BaseManipulator : public AZStd::enable_shared_from_this { public: AZ_CLASS_ALLOCATOR_DECL @@ -61,139 +60,181 @@ namespace AzToolsFramework using EntityComponentIds = AZStd::unordered_set; - /// Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed. - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. - /// @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the target manipulator in world space. - /// @return Return true if OnLeftMouseDownImpl was attached and will be used. + //! Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed. + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. + //! @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the + //! target manipulator in world space. + //! @return Return true if OnLeftMouseDownImpl was attached and will be used. bool OnLeftMouseDown(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance); - /// Callback for the event when this manipulator is active and the left mouse button is released. - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. + //! Callback for the event when this manipulator is active and the left mouse button is released. + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. void OnLeftMouseUp(const ViewportInteraction::MouseInteraction& interaction); - /// Callback for the event when the mouse pointer is over this manipulator and the right mouse button is pressed . - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. - /// @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the target manipulator in world space. - /// @return Return true if OnRightMouseDownImpl was attached and will be used. + //! Callback for the event when the mouse pointer is over this manipulator and the right mouse button is pressed . + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. + //! @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the + //! target manipulator in world space. + //! @return Return true if OnRightMouseDownImpl was attached and will be used. bool OnRightMouseDown(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance); - /// Callback for the event when this manipulator is active and the right mouse button is released. - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. + //! Callback for the event when this manipulator is active and the right mouse button is released. + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. void OnRightMouseUp(const ViewportInteraction::MouseInteraction& interaction); - /// Callback for the event when this manipulator is active and the mouse is moved. - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. + //! Callback for the event when this manipulator is active and the mouse is moved. + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. void OnMouseMove(const ViewportInteraction::MouseInteraction& interaction); - /// Callback for the event when this manipulator is active and the mouse wheel is scrolled. - /// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer. + //! Callback for the event when this manipulator is active and the mouse wheel is scrolled. + //! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera + //! through the mouse pointer. void OnMouseWheel(const ViewportInteraction::MouseInteraction& interaction); - /// This function changes the state indicating whether the manipulator is under the mouse pointer. - /// It is called in the event of OnMouseMove and OnMouseWheel only when there is no manipulator currently performing actions. + //! This function changes the state indicating whether the manipulator is under the mouse pointer. + //! It is called in the event of OnMouseMove and OnMouseWheel only when there is no manipulator currently performing actions. bool OnMouseOver(ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction); - /// Register itself to a manipulator manager so that it can receive various mouse events and perform manipulations. - /// @param managerId The id identifying a unique manipulator manager. + //! Register itself to a manipulator manager so that it can receive various mouse events and perform manipulations. + //! @param managerId The id identifying a unique manipulator manager. void Register(ManipulatorManagerId managerId); - /// Unregister itself from the manipulator manager it was registered with. + //! Unregister itself from the manipulator manager it was registered with. void Unregister(); - /// Bounds will need to be recalculated next time we render. + //! Bounds will need to be recalculated next time we render. void SetBoundsDirty(); - /// Is this manipulator currently registered with a manipulator manager. + //! Is this manipulator currently registered with a manipulator manager. bool Registered() const { - return m_manipulatorId != InvalidManipulatorId && - m_manipulatorManagerId != InvalidManipulatorManagerId; + return m_manipulatorId != InvalidManipulatorId && m_manipulatorManagerId != InvalidManipulatorManagerId; } - /// Is the manipulator in the middle of an action (between mouse down and mouse up). - bool PerformingAction() const { return m_performingAction; } + //! Is the manipulator in the middle of an action (between mouse down and mouse up). + bool PerformingAction() const + { + return m_performingAction; + } - /// Is the mouse currently over the manipulator (intersecting manipulator bound). - bool MouseOver() const { return m_mouseOver; } + //! Is the mouse currently over the manipulator (intersecting manipulator bound). + bool MouseOver() const + { + return m_mouseOver; + } - /// The unique id of this manipulator. - ManipulatorId GetManipulatorId() const { return m_manipulatorId; } + //! The unique id of this manipulator. + ManipulatorId GetManipulatorId() const + { + return m_manipulatorId; + } - /// The unique id of the manager this manipulator was registered with. - ManipulatorManagerId GetManipulatorManagerId() const { return m_manipulatorManagerId; } + //! The unique id of the manager this manipulator was registered with. + ManipulatorManagerId GetManipulatorManagerId() const + { + return m_manipulatorManagerId; + } - /// Returns all EntityComponentIdPairs associated with this manipulator. + //! Returns all EntityComponentIdPairs associated with this manipulator. const EntityComponentIds& EntityComponentIdPairs() const { return m_entityComponentIdPairs; } - /// Add an entity and component the manipulator is responsible for. + //! Add an entity and component the manipulator is responsible for. void AddEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair); - /// Remove an entity from being affected by this manipulator. - /// @note All components on this entity registered with the manipulator will be removed. + //! Remove an entity from being affected by this manipulator. + //! @note All components on this entity registered with the manipulator will be removed. EntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId); - /// Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator. + //! Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator. EntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair); - /// Is this entity currently being tracked by this manipulator. + //! Is this entity currently being tracked by this manipulator. bool HasEntityId(AZ::EntityId entityId) const; - /// Is this entity component pair currently being tracked by this manipulator. + //! Is this entity component pair currently being tracked by this manipulator. bool HasEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) const; - /// Forward a mouse over event in a case where we need the manipulator to immediately refresh. - /// @note Only call this when a mouse over event has just happened. + //! Forward a mouse over event in a case where we need the manipulator to immediately refresh. + //! @note Only call this when a mouse over event has just happened. void ForwardMouseOverEvent(const ViewportInteraction::MouseInteraction& interaction); static const AZ::Color s_defaultMouseOverColor; protected: - /// Protected constructor. + //! Protected constructor. BaseManipulator() = default; - /// Called when unregistering - users of manipulators should not call it directly. + //! Called when unregistering - users of manipulators should not call it directly. void Invalidate(); - /// The implementation to override in a derived class for Invalidate. - virtual void InvalidateImpl() {} + //! The implementation to override in a derived class for Invalidate. + virtual void InvalidateImpl() + { + } - /// The implementation to override in a derived class for OnLeftMouseDown. - /// Note: When implementing this function you must also call AttachLeftMouseDownImpl to ensure - /// m_onLeftMouseDownImpl is set to OnLeftMouseDownImpl, otherwise it will not be called - virtual void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) {} - void AttachLeftMouseDownImpl() { m_onLeftMouseDownImpl = &BaseManipulator::OnLeftMouseDownImpl; } + //! The implementation to override in a derived class for OnLeftMouseDown. + //! Note: When implementing this function you must also call AttachLeftMouseDownImpl to ensure + //! m_onLeftMouseDownImpl is set to OnLeftMouseDownImpl, otherwise it will not be called + virtual void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) + { + } - /// The implementation to override in a derived class for OnRightMouseDown. - /// Note: When implementing this function you must also call AttachRightMouseDownImpl to ensure - /// m_onRightMouseDownImpl is set to OnRightMouseDownImpl, otherwise it will not be called - virtual void OnRightMouseDownImpl( - const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) {} - void AttachRightMouseDownImpl() { m_onRightMouseDownImpl = &BaseManipulator::OnRightMouseDownImpl; } + void AttachLeftMouseDownImpl() + { + m_onLeftMouseDownImpl = &BaseManipulator::OnLeftMouseDownImpl; + } - /// The implementation to override in a derived class for OnLeftMouseUp. - virtual void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {} + //! The implementation to override in a derived class for OnRightMouseDown. + //! Note: When implementing this function you must also call AttachRightMouseDownImpl to ensure + //! m_onRightMouseDownImpl is set to OnRightMouseDownImpl, otherwise it will not be called + virtual void OnRightMouseDownImpl(const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) + { + } - /// The implementation to override in a derived class for OnRightMouseUp. - virtual void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {} + void AttachRightMouseDownImpl() + { + m_onRightMouseDownImpl = &BaseManipulator::OnRightMouseDownImpl; + } - /// The implementation to override in a derived class for OnMouseMove. - virtual void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {} + //! The implementation to override in a derived class for OnLeftMouseUp. + virtual void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) + { + } - /// The implementation to override in a derived class for OnMouseOver. - virtual void OnMouseOverImpl( - ManipulatorId /*manipulatorId*/, const ViewportInteraction::MouseInteraction& /*interaction*/) {} + //! The implementation to override in a derived class for OnRightMouseUp. + virtual void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) + { + } - /// The implementation to override in a derived class for OnMouseWheel. - virtual void OnMouseWheelImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {} + //! The implementation to override in a derived class for OnMouseMove. + virtual void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) + { + } - /// The implementation to override in a derived class for SetBoundsDirty. - virtual void SetBoundsDirtyImpl() {} + //! The implementation to override in a derived class for OnMouseOver. + virtual void OnMouseOverImpl(ManipulatorId /*manipulatorId*/, const ViewportInteraction::MouseInteraction& /*interaction*/) + { + } - /// Rendering for the manipulator - it is recommended drawing be delegated to a ManipulatorView. + //! The implementation to override in a derived class for OnMouseWheel. + virtual void OnMouseWheelImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) + { + } + + //! The implementation to override in a derived class for SetBoundsDirty. + virtual void SetBoundsDirtyImpl() + { + } + + //! Rendering for the manipulator - it is recommended drawing be delegated to a ManipulatorView. virtual void Draw( const ManipulatorManagerState& managerState, AzFramework::DebugDisplayRequests& debugDisplay, @@ -202,39 +243,39 @@ namespace AzToolsFramework private: friend class ManipulatorManager; - AZStd::unordered_set m_entityComponentIdPairs; ///< The entities this manipulator is associated with. + AZStd::unordered_set m_entityComponentIdPairs; //!< The entities this manipulator is associated with. - ManipulatorId m_manipulatorId = InvalidManipulatorId; ///< The unique id of this manipulator. - ManipulatorManagerId m_manipulatorManagerId = InvalidManipulatorManagerId; ///< The manager this manipulator was registered with. - UndoSystem::URSequencePoint* m_undoBatch = nullptr; ///< Undo active while mouse is pressed. - bool m_performingAction = false; ///< After mouse down and before mouse up. - bool m_mouseOver = false; ///< Is the mouse pointer over the manipulator bound. + ManipulatorId m_manipulatorId = InvalidManipulatorId; //!< The unique id of this manipulator. + ManipulatorManagerId m_manipulatorManagerId = InvalidManipulatorManagerId; //!< The manager this manipulator was registered with. + UndoSystem::URSequencePoint* m_undoBatch = nullptr; //!< Undo active while mouse is pressed. + bool m_performingAction = false; //!< After mouse down and before mouse up. + bool m_mouseOver = false; //!< Is the mouse pointer over the manipulator bound. - /// Member function pointers to OnLeftMouseDownImpl and OnRightMouseDownImpl. - /// Set in AttachLeft/RightMouseDownImpl. + //! Member function pointers to OnLeftMouseDownImpl and OnRightMouseDownImpl. + //! Set in AttachLeft/RightMouseDownImpl. void (BaseManipulator::*m_onLeftMouseDownImpl)( const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) = nullptr; void (BaseManipulator::*m_onRightMouseDownImpl)( const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) = nullptr; - /// Update the mouseOver state for this manipulator. + //! Update the mouseOver state for this manipulator. void UpdateMouseOver(ManipulatorId manipulatorId); - /// Manage correctly ending the undo batch. + //! Manage correctly ending the undo batch. void EndUndoBatch(); - /// Record an action as having started. + //! Record an action as having started. void BeginAction(); - /// Record an action as having stopped. + //! Record an action as having stopped. void EndAction(); - /// Let other systems (UI) know that a component property has been modified by a manipulator. + //! Let other systems (UI) know that a component property has been modified by a manipulator. void NotifyEntityComponentPropertyChanged(); }; - /// Base class to be used when composing aggregate manipulator types - wraps some - /// common functionality all manipulators need. + //! Base class to be used when composing aggregate manipulator types - wraps some + //! common functionality all manipulators need. class Manipulators { public: @@ -249,8 +290,10 @@ namespace AzToolsFramework bool PerformingAction(); bool Registered(); - /// Refresh the Manipulator and/or View based on the current view position. - virtual void RefreshView(const AZ::Vector3& /*worldViewPosition*/) {} + //! Refresh the Manipulator and/or View based on the current view position. + virtual void RefreshView(const AZ::Vector3& /*worldViewPosition*/) + { + } const AZ::Transform& GetLocalTransform() const; const AZ::Transform& GetSpace() const; @@ -262,39 +305,59 @@ namespace AzToolsFramework void SetNonUniformScale(const AZ::Vector3& nonUniformScale); protected: - /// Common processing for base manipulator type - Implement for all - /// individual manipulators used in an aggregate manipulator. + //! Common processing for base manipulator type - Implement for all + //! individual manipulators used in an aggregate manipulator. virtual void ProcessManipulators(const AZStd::function&) = 0; - ///@{ - /// Allows implementers to perform additional logic when updating the location of the manipulator group. - virtual void SetSpaceImpl([[maybe_unused]] const AZ::Transform& worldFromLocal) {} - virtual void SetLocalTransformImpl([[maybe_unused]] const AZ::Transform& localTransform) {} - virtual void SetLocalPositionImpl([[maybe_unused]] const AZ::Vector3& localPosition) {} - virtual void SetLocalOrientationImpl([[maybe_unused]] const AZ::Quaternion& localOrientation) {} - virtual void SetNonUniformScaleImpl([[maybe_unused]] const AZ::Vector3& nonUniformScale) {} - ///@} + //!@{ + //! Allows implementers to perform additional logic when updating the location of the manipulator group. + virtual void SetSpaceImpl([[maybe_unused]] const AZ::Transform& worldFromLocal) + { + } - ManipulatorSpaceWithLocalTransform m_manipulatorSpaceWithLocalTransform; ///< The space and local transform for the manipulators. + virtual void SetLocalTransformImpl([[maybe_unused]] const AZ::Transform& localTransform) + { + } + + virtual void SetLocalPositionImpl([[maybe_unused]] const AZ::Vector3& localPosition) + { + } + + virtual void SetLocalOrientationImpl([[maybe_unused]] const AZ::Quaternion& localOrientation) + { + } + + virtual void SetNonUniformScaleImpl([[maybe_unused]] const AZ::Vector3& nonUniformScale) + { + } + //!@} + + ManipulatorSpaceWithLocalTransform m_manipulatorSpaceWithLocalTransform; //!< The space and local transform for the manipulators. }; namespace Internal { - /// This helper function calculates the intersecting point between a ray and a plane. - /// @param rayOrigin The origin of the ray to test. - /// @param rayDirection The direction of the ray to test. - /// @param maxRayLength - /// @param pointOnPlane A point on the plane. - /// @param planeNormal The normal vector of the plane. - /// @param[out] resultIntersectingPoint This stores the result intersecting point. It will be left unchanged - /// if there is no intersection between the ray and the plane. - /// @return Was there an intersection - bool CalculateRayPlaneIntersectingPoint(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, - const AZ::Vector3& pointOnPlane, const AZ::Vector3& planeNormal, AZ::Vector3& resultIntersectingPoint); + //! This helper function calculates the intersecting point between a ray and a plane. + //! @param rayOrigin The origin of the ray to test. + //! @param rayDirection The direction of the ray to test. + //! @param maxRayLength The maximum length of the ray to test. + //! @param pointOnPlane A point on the plane. + //! @param planeNormal The normal vector of the plane. + //! @param[out] resultIntersectingPoint This stores the result intersecting point. It will be left unchanged + //! if there is no intersection between the ray and the plane. + //! @return Was there an intersection + bool CalculateRayPlaneIntersectingPoint( + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZ::Vector3& pointOnPlane, + const AZ::Vector3& planeNormal, + AZ::Vector3& resultIntersectingPoint); - /// Returns startLocalHitPosition if currentLocalHitPosition is further away than the camera's far clip plane. + //! Returns startLocalHitPosition if currentLocalHitPosition is further away than the camera's far clip plane. AZ::Vector3 TryConstrainHitPositionToView( - const AZ::Vector3& currentLocalHitPosition, const AZ::Vector3& startLocalHitPosition, - const AZ::Transform& localFromWorld, const AzFramework::CameraState& cameraState); - } + const AZ::Vector3& currentLocalHitPosition, + const AZ::Vector3& startLocalHitPosition, + const AZ::Transform& localFromWorld, + const AzFramework::CameraState& cameraState); + } // namespace Internal } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BoxManipulatorRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BoxManipulatorRequestBus.h index 05da73fa20..69920f5f52 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BoxManipulatorRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BoxManipulatorRequestBus.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -21,31 +21,30 @@ namespace AZ namespace AzToolsFramework { - /// Interface for handling box manipulator requests. - /// Used by \ref BoxComponentMode. - class BoxManipulatorRequests - : public AZ::EntityComponentBus + //! Interface for handling box manipulator requests. + //! Used by \ref BoxComponentMode. + class BoxManipulatorRequests : public AZ::EntityComponentBus { public: - /// Get the X/Y/Z dimensions of the box shape/collider. + //! Get the X/Y/Z dimensions of the box shape/collider. virtual AZ::Vector3 GetDimensions() = 0; - /// Set the X/Y/Z dimensions of the box shape/collider. + //! Set the X/Y/Z dimensions of the box shape/collider. virtual void SetDimensions(const AZ::Vector3& dimensions) = 0; - /// Get the transform of the box shape/collider. - /// This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus - /// because a collider may have an additional translation/orientation offset from - /// the Entity transform. + //! Get the transform of the box shape/collider. + //! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus + //! because a collider may have an additional translation/orientation offset from + //! the Entity transform. virtual AZ::Transform GetCurrentTransform() = 0; - /// Get the scale currently applied to the box. - /// With the Box Shape, the largest x/y/z component is taken - /// so scale is always uniform, with colliders the scale may - /// be different per component. + //! Get the scale currently applied to the box. + //! With the Box Shape, the largest x/y/z component is taken + //! so scale is always uniform, with colliders the scale may + //! be different per component. virtual AZ::Vector3 GetBoxScale() = 0; protected: ~BoxManipulatorRequests() = default; }; - /// Type to inherit to implement BoxManipulatorRequests + //! Type to inherit to implement BoxManipulatorRequests using BoxManipulatorRequestBus = AZ::EBus; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp index 55a8464ba6..c8be488c91 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorVertexSelection.h" @@ -16,10 +16,10 @@ #include #include #include -#include #include -#include #include +#include +#include #include #include #include @@ -37,7 +37,7 @@ using Vertex3LookupReverseIter = namespace std { - template <> + template<> struct iterator_traits { using difference_type = typename Vertex2LookupReverseIter::difference_type; @@ -47,7 +47,7 @@ namespace std using reference = typename Vertex2LookupReverseIter::reference; }; - template <> + template<> struct iterator_traits { using difference_type = typename Vertex3LookupReverseIter::difference_type; @@ -56,7 +56,7 @@ namespace std using pointer = typename Vertex3LookupReverseIter::pointer; using reference = typename Vertex3LookupReverseIter::reference; }; -} +} // namespace std namespace AzToolsFramework { @@ -73,14 +73,11 @@ namespace AzToolsFramework OnEntityComponentPropertyChanged(entityComponentIdPair); // ensure property grid values are refreshed - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, - Refresh_EntireTree); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_EntireTree); } template - bool EditorVertexSelectionBase::HandleMouse( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + bool EditorVertexSelectionBase::HandleMouse(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { m_editorBoxSelect.HandleMouseInteraction(mouseInteraction); @@ -115,18 +112,17 @@ namespace AzToolsFramework } template - void EditorVertexSelectionBase::SnapVerticesToTerrain( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + void EditorVertexSelectionBase::SnapVerticesToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { ScopedUndoBatch surfaceSnapUndo("Snap to Surface"); ScopedUndoBatch::MarkEntityDirty(GetEntityId()); const int viewportId = mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId; // get unsnapped terrain position (world space) - AZ::Vector3 worldSurfacePosition = AZ::Vector3::CreateZero();; + AZ::Vector3 worldSurfacePosition = AZ::Vector3::CreateZero(); + ; ViewportInteraction::MainEditorViewportInteractionRequestBus::EventResult( - worldSurfacePosition, viewportId, - &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::PickTerrain, + worldSurfacePosition, viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::PickTerrain, mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); AZ::Transform worldFromLocal; @@ -136,8 +132,7 @@ namespace AzToolsFramework // convert to local space - snap if enabled const GridSnapParameters gridSnapParams = GridSnapSettings(viewportId); const AZ::Vector3 localFinalSurfacePosition = gridSnapParams.m_gridSnap - ? CalculateSnappedTerrainPosition( - worldSurfacePosition, worldFromLocal, viewportId, gridSnapParams.m_gridSize) + ? CalculateSnappedTerrainPosition(worldSurfacePosition, worldFromLocal, viewportId, gridSnapParams.m_gridSize) : localFromWorld.TransformPoint(worldSurfacePosition); SetSelectedPosition(localFinalSurfacePosition); @@ -145,17 +140,16 @@ namespace AzToolsFramework OnEntityComponentPropertyChanged(GetEntityComponentIdPair()); // ensure property grid values are refreshed - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, - Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); } - /// Iterate over all vertices currently associated with the translation manipulator and update their - /// positions by taking their starting positions and modifying them by an offset. + // iterate over all vertices currently associated with the translation manipulator and update their + // positions by taking their starting positions and modifying them by an offset. template void EditorVertexSelectionBase::UpdateManipulatorsAndVerticesFromOffset( IndexedTranslationManipulator& translationManipulator, - const AZ::Vector3& localManipulatorStartPosition, const AZ::Vector3& localManipulatorOffset) + const AZ::Vector3& localManipulatorStartPosition, + const AZ::Vector3& localManipulatorOffset) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -164,22 +158,19 @@ namespace AzToolsFramework AZ::FixedVerticesRequestBus::Bind(fixedVertices, GetEntityId()); translationManipulator.Process( - [this, localManipulatorOffset, fixedVertices] - (typename IndexedTranslationManipulator::VertexLookup& vertex) - { - vertex.m_offset = AZ::AdaptVertexIn(localManipulatorOffset); + [this, localManipulatorOffset, fixedVertices](typename IndexedTranslationManipulator::VertexLookup& vertex) + { + vertex.m_offset = AZ::AdaptVertexIn(localManipulatorOffset); - bool updated = false; - const Vertex vertexPosition = vertex.m_start + vertex.m_offset; - AZ::FixedVerticesRequestBus::EventResult( - updated, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::UpdateVertex, - vertex.m_index, vertexPosition); + bool updated = false; + const Vertex vertexPosition = vertex.m_start + vertex.m_offset; + AZ::FixedVerticesRequestBus::EventResult( + updated, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::UpdateVertex, vertex.m_index, vertexPosition); - m_selectionManipulators[vertex.m_index]->SetLocalPosition(AZ::AdaptVertexOut(vertexPosition)); - }); + m_selectionManipulators[vertex.m_index]->SetLocalPosition(AZ::AdaptVertexOut(vertexPosition)); + }); - m_translationManipulator->m_manipulator.SetLocalPosition( - localManipulatorStartPosition + localManipulatorOffset); + m_translationManipulator->m_manipulator.SetLocalPosition(localManipulatorStartPosition + localManipulatorOffset); // after vertex positions have changed, anything else which relies on their positions may update if (m_onVertexPositionsUpdated) @@ -188,11 +179,10 @@ namespace AzToolsFramework } } - /// In OnMouseDown for various manipulators (linear/planar/surface), ensure we record the vertex starting position - /// for each vertex associated with the translation manipulator to use with offset calculations when updating. + // in OnMouseDown for various manipulators (linear/planar/surface), ensure we record the vertex starting position + // for each vertex associated with the translation manipulator to use with offset calculations when updating. template - void InitializeVertexLookup( - IndexedTranslationManipulator& translationManipulator, const AZ::EntityId entityId) + void InitializeVertexLookup(IndexedTranslationManipulator& translationManipulator, const AZ::EntityId entityId) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -201,29 +191,28 @@ namespace AzToolsFramework AZ::FixedVerticesRequestBus::Bind(fixedVertices, entityId); translationManipulator.Process( - [fixedVertices] - (typename IndexedTranslationManipulator::VertexLookup& vertexLookup) - { - Vertex vertex; - bool found = false; - AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertexLookup.m_index, vertex); - - if (found) + [fixedVertices](typename IndexedTranslationManipulator::VertexLookup& vertexLookup) { - vertexLookup.m_start = vertex; - vertexLookup.m_offset = Vertex::CreateZero(); - } - }); + Vertex vertex; + bool found = false; + AZ::FixedVerticesRequestBus::EventResult( + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertexLookup.m_index, vertex); + + if (found) + { + vertexLookup.m_start = vertex; + vertexLookup.m_offset = Vertex::CreateZero(); + } + }); } - /// Create a translation manipulator for a specific vertex and setup its corresponding callbacks etc. + // create a translation manipulator for a specific vertex and setup its corresponding callbacks etc. template void EditorVertexSelectionBase::CreateTranslationManipulator( const AZ::EntityComponentIdPair& entityComponentIdPair, const ManipulatorManagerId managerId, - const Vertex& vertex, size_t vertexIndex) + const Vertex& vertex, + size_t vertexIndex) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -250,65 +239,65 @@ namespace AzToolsFramework // linear manipulator callbacks m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseDownCallback( [this]([[maybe_unused]] const LinearManipulator::Action& action) - { - BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId()); - }); + { + BeginBatchMovement(); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); + }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseMoveCallback( [this](const LinearManipulator::Action& action) - { - UpdateManipulatorsAndVerticesFromOffset( - *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); - }); + { + UpdateManipulatorsAndVerticesFromOffset( + *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); + }); m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseUpCallback( [this]([[maybe_unused]] const LinearManipulator::Action& action) - { - EndBatchMovement(); - }); + { + EndBatchMovement(); + }); // planar manipulator callbacks m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseDownCallback( [this]([[maybe_unused]] const PlanarManipulator::Action& action) - { - BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId()); - }); + { + BeginBatchMovement(); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); + }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseMoveCallback( [this](const PlanarManipulator::Action& action) - { - UpdateManipulatorsAndVerticesFromOffset( - *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); - }); + { + UpdateManipulatorsAndVerticesFromOffset( + *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); + }); m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseUpCallback( [this]([[maybe_unused]] const PlanarManipulator::Action& action) - { - EndBatchMovement(); - }); + { + EndBatchMovement(); + }); // surface manipulator callbacks m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseDownCallback( [this]([[maybe_unused]] const SurfaceManipulator::Action& action) - { - BeginBatchMovement(); - InitializeVertexLookup(*m_translationManipulator, GetEntityId()); - }); + { + BeginBatchMovement(); + InitializeVertexLookup(*m_translationManipulator, GetEntityId()); + }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseMoveCallback( [this](const SurfaceManipulator::Action& action) - { - UpdateManipulatorsAndVerticesFromOffset( - *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); - }); + { + UpdateManipulatorsAndVerticesFromOffset( + *m_translationManipulator, action.m_start.m_localPosition, action.LocalPositionOffset()); + }); m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseUpCallback( [this]([[maybe_unused]] const SurfaceManipulator::Action& action) - { - EndBatchMovement(); - }); + { + EndBatchMovement(); + }); // register the m_translation manipulator so it appears where the selection manipulator previously was m_translationManipulator->m_manipulator.Register(managerId); @@ -330,9 +319,9 @@ namespace AzToolsFramework AZStd::transform( vertexLookups.begin(), vertexLookups.end(), AZStd::back_inserter(vertexIndices), [](const typename IndexedTranslationManipulator::VertexLookup& vertexLookup) - { - return vertexLookup.m_index; - }); + { + return vertexLookup.m_index; + }); return vertexIndices; } @@ -348,12 +337,13 @@ namespace AzToolsFramework bool m_additive = true; // is the box select adding or removing things from the selection }; - template void DoBoxSelect( - const AZ::EntityId entityId, BoxSelectData& boxSelectData, + const AZ::EntityId entityId, + BoxSelectData& boxSelectData, const ViewportInteraction::KeyboardModifiers keyboardModifiers, - const int viewportId, const EditorBoxSelect& editorBoxSelect, + const int viewportId, + const EditorBoxSelect& editorBoxSelect, const AZStd::vector>& selectionManipulators) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -384,8 +374,7 @@ namespace AzToolsFramework if (editorBoxSelect.BoxRegion()) { AZ::Transform worldFromLocal; - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); // bind FixedVerticesRequestBus for improved performance typename AZ::FixedVerticesRequestBus::BusPtr fixedVertices; @@ -396,8 +385,7 @@ namespace AzToolsFramework Vertex localVertex; bool found = false; AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertexIndex, localVertex); + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertexIndex, localVertex); const AZ::Vector3 worldVertex = worldFromLocal.TransformPoint(AZ::AdaptVertexOut(localVertex)); const AzFramework::ScreenPoint screenPosition = GetScreenPosition(viewportId, worldVertex); @@ -406,8 +394,8 @@ namespace AzToolsFramework if (editorBoxSelect.BoxRegion()->contains(ViewportInteraction::QPointFromScreenPoint(screenPosition))) { // see if vertexIndex is in active selection - auto vertexIt = AZStd::find( - boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); + auto vertexIt = + AZStd::find(boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); if (!keyboardModifiers.Ctrl()) { @@ -437,8 +425,8 @@ namespace AzToolsFramework else { // not in box region - see if vertexIndex is in delta selection - auto vertexItDelta = AZStd::find( - boxSelectData.m_deltaSelection.begin(), boxSelectData.m_deltaSelection.end(), vertexIndex); + auto vertexItDelta = + AZStd::find(boxSelectData.m_deltaSelection.begin(), boxSelectData.m_deltaSelection.end(), vertexIndex); // if we find the vertex in the delta selection if (vertexItDelta != boxSelectData.m_deltaSelection.end()) @@ -451,8 +439,8 @@ namespace AzToolsFramework boxSelectData.m_deltaSelection.erase(vertexItDelta); // remove the vertex from the active selection as well - auto vertexItStart = AZStd::find( - boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); + auto vertexItStart = + AZStd::find(boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); if (vertexItStart != boxSelectData.m_activeSelection.end()) { @@ -467,8 +455,8 @@ namespace AzToolsFramework boxSelectData.m_deltaSelection.erase(vertexItDelta); // also add it back to the active selection - auto vertexItStart = AZStd::find( - boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); + auto vertexItStart = + AZStd::find(boxSelectData.m_activeSelection.begin(), boxSelectData.m_activeSelection.end(), vertexIndex); if (vertexItStart == boxSelectData.m_activeSelection.end()) { @@ -491,7 +479,8 @@ namespace AzToolsFramework template void EditorVertexSelectionBase::Create( - const AZ::EntityComponentIdPair& entityComponentIdPair, const ManipulatorManagerId managerId, + const AZ::EntityComponentIdPair& entityComponentIdPair, + const ManipulatorManagerId managerId, AZStd::unique_ptr hoverSelection, const TranslationManipulators::Dimensions dimensions, const TranslationManipulatorConfiguratorFn translationManipulatorConfigurator) @@ -509,8 +498,7 @@ namespace AzToolsFramework AZ::FixedVerticesRequestBus::Bind(fixedVertices, GetEntityId()); size_t vertexCount = 0; - AZ::FixedVerticesRequestBus::EventResult( - vertexCount, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::Size); + AZ::FixedVerticesRequestBus::EventResult(vertexCount, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::Size); m_selectionManipulators.reserve(vertexCount); // initialize manipulators for all spline vertices @@ -519,12 +507,10 @@ namespace AzToolsFramework Vertex vertex; bool found = false; AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertexIndex, vertex); + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertexIndex, vertex); - m_selectionManipulators.push_back(SelectionManipulator::MakeShared( - WorldFromLocalWithUniformScale(GetEntityId()), - GetNonUniformScale(GetEntityId()))); + m_selectionManipulators.push_back( + SelectionManipulator::MakeShared(WorldFromLocalWithUniformScale(GetEntityId()), GetNonUniformScale(GetEntityId()))); const auto& selectionManipulator = m_selectionManipulators.back(); selectionManipulator->Register(managerId); @@ -539,156 +525,153 @@ namespace AzToolsFramework m_editorBoxSelect.InstallLeftMouseDown( [this, vertexBoxSelectData](const ViewportInteraction::MouseInteractionEvent& /*mouseInteraction*/) - { - // grab currently selected entities (the starting selection) - vertexBoxSelectData->m_startSelection = m_translationManipulator - ? MapFromLookupsToIndices(m_translationManipulator->m_vertices) - : AZStd::vector(); + { + // grab currently selected entities (the starting selection) + vertexBoxSelectData->m_startSelection = m_translationManipulator + ? MapFromLookupsToIndices(m_translationManipulator->m_vertices) + : AZStd::vector(); - // active selection is the same as start selection on mouse down - vertexBoxSelectData->m_activeSelection = vertexBoxSelectData->m_startSelection; + // active selection is the same as start selection on mouse down + vertexBoxSelectData->m_activeSelection = vertexBoxSelectData->m_startSelection; - size_t size = 0; - AZ::FixedVerticesRequestBus::EventResult( - size, GetEntityId(), &AZ::FixedVerticesRequestBus::Handler::Size); + size_t size = 0; + AZ::FixedVerticesRequestBus::EventResult(size, GetEntityId(), &AZ::FixedVerticesRequestBus::Handler::Size); - // populate vector of all indices in container to compare against - vertexBoxSelectData->m_all.resize(size); - std::iota(vertexBoxSelectData->m_all.begin(), vertexBoxSelectData->m_all.end(), static_cast(0)); - }); + // populate vector of all indices in container to compare against + vertexBoxSelectData->m_all.resize(size); + std::iota(vertexBoxSelectData->m_all.begin(), vertexBoxSelectData->m_all.end(), static_cast(0)); + }); m_editorBoxSelect.InstallMouseMove( [this, vertexBoxSelectData](const ViewportInteraction::MouseInteractionEvent& mouseInteraction) - { - DoBoxSelect( - GetEntityId(), *vertexBoxSelectData, mouseInteraction.m_mouseInteraction.m_keyboardModifiers, - mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId, - m_editorBoxSelect, m_selectionManipulators); - }); - - m_editorBoxSelect.InstallLeftMouseUp([this, vertexBoxSelectData]() - { - if (vertexBoxSelectData->m_additive) { - // bind FixedVerticesRequestBus for improved performance - typename AZ::FixedVerticesRequestBus::BusPtr fixedVertices; - AZ::FixedVerticesRequestBus::Bind(fixedVertices, GetEntityId()); + DoBoxSelect( + GetEntityId(), *vertexBoxSelectData, mouseInteraction.m_mouseInteraction.m_keyboardModifiers, + mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId, m_editorBoxSelect, m_selectionManipulators); + }); - const AZ::EntityComponentIdPair entityComponentIdPair = m_entityComponentIdPair; - for (size_t vertexIndex : vertexBoxSelectData->m_deltaSelection) - { - Vertex vertex; - bool found = false; - AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertexIndex, vertex); - - // if we already have a translation manipulator, add additional vertices to it - if (m_translationManipulator) - { - // otherwise add the new selected vertex - m_translationManipulator->m_vertices.push_back( - typename IndexedTranslationManipulator::VertexLookup{ vertex, Vertex::CreateZero(), vertexIndex }); - } - else - { - // create a new translation manipulator if one did not already exist with the first vertex - CreateTranslationManipulator(entityComponentIdPair, m_manipulatorManagerId, vertex, vertexIndex); - // default to ensuring selection manipulators are 'selected' - m_selectionManipulators[vertexIndex]->Select(); - } - } - } - else - { - // removing vertices with an active translation manipulator - if (m_translationManipulator) - { - // iterate through all delta vertices (ones that were either - // added or removed during selection) and remove them - for (size_t vertexIndex : vertexBoxSelectData->m_deltaSelection) - { - auto vertexIt = AZStd::find_if( - m_translationManipulator->m_vertices.begin(), m_translationManipulator->m_vertices.end(), - [vertexIndex](const auto& vertexLookup) - { - return vertexLookup.m_index == vertexIndex; - }); - - // remove vertex from translation manipulator - if (vertexIt != m_translationManipulator->m_vertices.end()) - { - m_translationManipulator->m_vertices.erase(vertexIt); - - // ensure it is registered to receive input and draw - if (!m_selectionManipulators[vertexIndex]->Registered()) - { - m_selectionManipulators[vertexIndex]->Register(m_manipulatorManagerId); - } - } - } - - // if we have no vertices left, clear selection (restore all selection - // manipulators and destroy translation manipulator) - if (m_translationManipulator->m_vertices.empty()) - { - ClearSelected(); - } - } - } - - // with a selection of more than one or zero, we want to ensure all selection - // manipulators are registered (can be clicked on) - if (vertexBoxSelectData->m_activeSelection.size() > 1) - { - for (size_t vertexIndex : vertexBoxSelectData->m_activeSelection) - { - if (!m_selectionManipulators[vertexIndex]->Registered()) - { - m_selectionManipulators[vertexIndex]->Register(m_manipulatorManagerId); - } - } - } - // special case handling for only one vertex - don't want to display it when - // translation manipulator will be in exactly the same location - else if (vertexBoxSelectData->m_activeSelection.size() == 1) + m_editorBoxSelect.InstallLeftMouseUp( + [this, vertexBoxSelectData]() { if (vertexBoxSelectData->m_additive) { - m_selectionManipulators[vertexBoxSelectData->m_activeSelection[0]]->Unregister(); + // bind FixedVerticesRequestBus for improved performance + typename AZ::FixedVerticesRequestBus::BusPtr fixedVertices; + AZ::FixedVerticesRequestBus::Bind(fixedVertices, GetEntityId()); + + const AZ::EntityComponentIdPair entityComponentIdPair = m_entityComponentIdPair; + for (size_t vertexIndex : vertexBoxSelectData->m_deltaSelection) + { + Vertex vertex; + bool found = false; + AZ::FixedVerticesRequestBus::EventResult( + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertexIndex, vertex); + + // if we already have a translation manipulator, add additional vertices to it + if (m_translationManipulator) + { + // otherwise add the new selected vertex + m_translationManipulator->m_vertices.push_back( + typename IndexedTranslationManipulator::VertexLookup{ vertex, Vertex::CreateZero(), vertexIndex }); + } + else + { + // create a new translation manipulator if one did not already exist with the first vertex + CreateTranslationManipulator(entityComponentIdPair, m_manipulatorManagerId, vertex, vertexIndex); + // default to ensuring selection manipulators are 'selected' + m_selectionManipulators[vertexIndex]->Select(); + } + } } else { - m_selectionManipulators[vertexBoxSelectData->m_activeSelection[0]]->Register(m_manipulatorManagerId); + // removing vertices with an active translation manipulator + if (m_translationManipulator) + { + // iterate through all delta vertices (ones that were either + // added or removed during selection) and remove them + for (size_t vertexIndex : vertexBoxSelectData->m_deltaSelection) + { + auto vertexIt = AZStd::find_if( + m_translationManipulator->m_vertices.begin(), m_translationManipulator->m_vertices.end(), + [vertexIndex](const auto& vertexLookup) + { + return vertexLookup.m_index == vertexIndex; + }); + + // remove vertex from translation manipulator + if (vertexIt != m_translationManipulator->m_vertices.end()) + { + m_translationManipulator->m_vertices.erase(vertexIt); + + // ensure it is registered to receive input and draw + if (!m_selectionManipulators[vertexIndex]->Registered()) + { + m_selectionManipulators[vertexIndex]->Register(m_manipulatorManagerId); + } + } + } + + // if we have no vertices left, clear selection (restore all selection + // manipulators and destroy translation manipulator) + if (m_translationManipulator->m_vertices.empty()) + { + ClearSelected(); + } + } } - } - // update manipulator positions (ensure translation manipulator is - // centered on current selection) - RefreshTranslationManipulator(); + // with a selection of more than one or zero, we want to ensure all selection + // manipulators are registered (can be clicked on) + if (vertexBoxSelectData->m_activeSelection.size() > 1) + { + for (size_t vertexIndex : vertexBoxSelectData->m_activeSelection) + { + if (!m_selectionManipulators[vertexIndex]->Registered()) + { + m_selectionManipulators[vertexIndex]->Register(m_manipulatorManagerId); + } + } + } + // special case handling for only one vertex - don't want to display it when + // translation manipulator will be in exactly the same location + else if (vertexBoxSelectData->m_activeSelection.size() == 1) + { + if (vertexBoxSelectData->m_additive) + { + m_selectionManipulators[vertexBoxSelectData->m_activeSelection[0]]->Unregister(); + } + else + { + m_selectionManipulators[vertexBoxSelectData->m_activeSelection[0]]->Register(m_manipulatorManagerId); + } + } - // restore state once box select has completed - vertexBoxSelectData->m_startSelection.clear(); - vertexBoxSelectData->m_deltaSelection.clear(); - vertexBoxSelectData->m_activeSelection.clear(); - vertexBoxSelectData->m_all.clear(); - }); + // update manipulator positions (ensure translation manipulator is + // centered on current selection) + RefreshTranslationManipulator(); - m_editorBoxSelect.InstallDisplayScene( - [this, vertexBoxSelectData] - (const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& /*debugDisplay*/) - { - const auto keyboardModifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + // restore state once box select has completed + vertexBoxSelectData->m_startSelection.clear(); + vertexBoxSelectData->m_deltaSelection.clear(); + vertexBoxSelectData->m_activeSelection.clear(); + vertexBoxSelectData->m_all.clear(); + }); - // when modifiers change ensure we refresh box selection for immediate update - if (keyboardModifiers != m_editorBoxSelect.PreviousModifiers()) - { - DoBoxSelect( - GetEntityId(), *vertexBoxSelectData, keyboardModifiers, - viewportInfo.m_viewportId, m_editorBoxSelect, m_selectionManipulators); - } - }); + m_editorBoxSelect.InstallDisplayScene( + [this, vertexBoxSelectData](const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& /*debugDisplay*/) + { + const auto keyboardModifiers = ViewportInteraction::KeyboardModifiers( + ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + + // when modifiers change ensure we refresh box selection for immediate update + if (keyboardModifiers != m_editorBoxSelect.PreviousModifiers()) + { + DoBoxSelect( + GetEntityId(), *vertexBoxSelectData, keyboardModifiers, viewportInfo.m_viewportId, m_editorBoxSelect, + m_selectionManipulators); + } + }); AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId()); AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(GetEntityContextId()); @@ -734,12 +717,12 @@ namespace AzToolsFramework { // re-enable all selection manipulators associated with the translation // manipulator which is now being removed. - m_translationManipulator->Process([this]( - typename IndexedTranslationManipulator::VertexLookup& vertex) - { - m_selectionManipulators[vertex.m_index]->Register(m_manipulatorManagerId); - m_selectionManipulators[vertex.m_index]->Deselect(); - }); + m_translationManipulator->Process( + [this](typename IndexedTranslationManipulator::VertexLookup& vertex) + { + m_selectionManipulators[vertex.m_index]->Register(m_manipulatorManagerId); + m_selectionManipulators[vertex.m_index]->Deselect(); + }); m_translationManipulator->m_manipulator.Unregister(); m_translationManipulator.reset(); @@ -755,8 +738,7 @@ namespace AzToolsFramework template void EditorVertexSelectionBase::DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -767,8 +749,7 @@ namespace AzToolsFramework template void EditorVertexSelectionBase::DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -777,8 +758,7 @@ namespace AzToolsFramework template template::value>::type*> - void EditorVertexSelectionBase::UpdateManipulatorSpace( - const AzFramework::ViewportInfo& viewportInfo) + void EditorVertexSelectionBase::UpdateManipulatorSpace(const AzFramework::ViewportInfo& viewportInfo) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -789,23 +769,19 @@ namespace AzToolsFramework &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::ShowingWorldSpace); // update the manipulator to be in the correct space if it changed - if ( m_translationManipulator - && !m_translationManipulator->m_manipulator.PerformingAction() - && worldSpace != m_worldSpace) + if (m_translationManipulator && !m_translationManipulator->m_manipulator.PerformingAction() && worldSpace != m_worldSpace) { const AZ::Transform worldFromLocal = WorldFromLocalWithUniformScale(GetEntityId()); - m_translationManipulator->m_manipulator.SetLocalOrientation(worldSpace - ? QuaternionFromTransformNoScaling(worldFromLocal).GetInverseFull() - : AZ::Quaternion::CreateIdentity()); + m_translationManipulator->m_manipulator.SetLocalOrientation( + worldSpace ? QuaternionFromTransformNoScaling(worldFromLocal).GetInverseFull() : AZ::Quaternion::CreateIdentity()); m_worldSpace = worldSpace; } } template template::value>::type*> - void EditorVertexSelectionBase::UpdateManipulatorSpace( - const AzFramework::ViewportInfo& /*viewportInfo*/) const + void EditorVertexSelectionBase::UpdateManipulatorSpace(const AzFramework::ViewportInfo& /*viewportInfo*/) const { } @@ -813,8 +789,7 @@ namespace AzToolsFramework static bool CanDeleteSelection(const AZ::EntityId entityId, const int64_t selectedCount) { size_t vertexCount = 0; - AZ::VariableVerticesRequestBus::EventResult( - vertexCount, entityId, &AZ::VariableVerticesRequestBus::Handler::Size); + AZ::VariableVerticesRequestBus::EventResult(vertexCount, entityId, &AZ::VariableVerticesRequestBus::Handler::Size); // prevent deleting all vertices const int64_t remaining = aznumeric_cast(vertexCount) - selectedCount; @@ -825,9 +800,8 @@ namespace AzToolsFramework void EditorVertexSelectionVariable::ShowVertexDeletionWarning() { QMessageBox::information( - AzToolsFramework::GetActiveWindow(), "Information", - "It is not possible to delete all vertices.", - QMessageBox::Ok, QMessageBox::NoButton); + AzToolsFramework::GetActiveWindow(), "Information", "It is not possible to delete all vertices.", QMessageBox::Ok, + QMessageBox::NoButton); } template @@ -856,19 +830,19 @@ namespace AzToolsFramework EditorVertexSelectionBase::m_translationManipulator; // ensure we remove vertices in reverse order - std::sort(translationManipulator->m_vertices.rbegin(), translationManipulator->m_vertices.rend(), + std::sort( + translationManipulator->m_vertices.rbegin(), translationManipulator->m_vertices.rend(), [](const typename IndexedTranslationManipulator::VertexLookup& lhs, - const typename IndexedTranslationManipulator::VertexLookup& rhs) - { - return lhs.m_index < rhs.m_index; - }); + const typename IndexedTranslationManipulator::VertexLookup& rhs) + { + return lhs.m_index < rhs.m_index; + }); - translationManipulator->Process([this]( - typename IndexedTranslationManipulator::VertexLookup& vertex) - { - SafeRemoveVertex( - EditorVertexSelectionBase::GetEntityComponentIdPair(), vertex.m_index); - }); + translationManipulator->Process( + [this](typename IndexedTranslationManipulator::VertexLookup& vertex) + { + SafeRemoveVertex(EditorVertexSelectionBase::GetEntityComponentIdPair(), vertex.m_index); + }); translationManipulator->m_manipulator.Unregister(); translationManipulator.reset(); @@ -876,8 +850,7 @@ namespace AzToolsFramework if (EditorVertexSelectionBase::m_hoverSelection) { - EditorVertexSelectionBase::m_hoverSelection->Register( - EditorVertexSelectionBase::GetManipulatorManagerId()); + EditorVertexSelectionBase::m_hoverSelection->Register(EditorVertexSelectionBase::GetManipulatorManagerId()); } EditorVertexSelectionBase::SetState(EditorVertexSelectionBase::State::Selecting); @@ -895,11 +868,9 @@ namespace AzToolsFramework InitializeVertexLookup(*m_translationManipulator, GetEntityId()); // note: AdaptVertexIn/Out is to ensure we clamp the vertex local Z position to 0 if // dealing with Vector2s when setting the position of the manipulator. - const AZ::Vector3 localOffset = - localPosition - m_translationManipulator->m_manipulator.GetLocalTransform().GetTranslation(); + const AZ::Vector3 localOffset = localPosition - m_translationManipulator->m_manipulator.GetLocalTransform().GetTranslation(); UpdateManipulatorsAndVerticesFromOffset( - *m_translationManipulator, - AZ::AdaptVertexOut(AZ::AdaptVertexIn(localPosition)), + *m_translationManipulator, AZ::AdaptVertexOut(AZ::AdaptVertexIn(localPosition)), AZ::AdaptVertexOut(AZ::AdaptVertexIn(localOffset))); RefreshTranslationManipulator(); @@ -928,23 +899,20 @@ namespace AzToolsFramework // calculate average position of selected vertices for translation manipulator MidpointCalculator midpointCalculator; m_translationManipulator->Process( - [this, &midpointCalculator, fixedVertices] - (typename IndexedTranslationManipulator::VertexLookup& vertex) - { - Vertex v; - bool found = false; - AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertex.m_index, v); - - if (found) + [this, &midpointCalculator, fixedVertices](typename IndexedTranslationManipulator::VertexLookup& vertex) { - midpointCalculator.AddPosition(AZ::AdaptVertexOut(v)); - } - }); + Vertex v; + bool found = false; + AZ::FixedVerticesRequestBus::EventResult( + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertex.m_index, v); - m_translationManipulator->m_manipulator.SetLocalPosition( - AZ::AdaptVertexOut(midpointCalculator.CalculateMidpoint())); + if (found) + { + midpointCalculator.AddPosition(AZ::AdaptVertexOut(v)); + } + }); + + m_translationManipulator->m_manipulator.SetLocalPosition(AZ::AdaptVertexOut(midpointCalculator.CalculateMidpoint())); } } @@ -970,8 +938,7 @@ namespace AzToolsFramework Vertex vertex; bool found = false; AZ::FixedVerticesRequestBus::EventResult( - found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - manipulatorIndex, vertex); + found, fixedVertices, &AZ::FixedVerticesRequestBus::Handler::GetVertex, manipulatorIndex, vertex); if (found) { @@ -1037,39 +1004,41 @@ namespace AzToolsFramework } } - /// Handle correctly selecting/deselecting vertices in a vertex selection. + // handle correctly selecting/deselecting vertices in a vertex selection. template void EditorVertexSelectionBase::SelectionManipulatorSelectCallback( - const size_t vertexIndex, const ViewportInteraction::MouseInteraction& interaction, - const AZ::EntityComponentIdPair& entityComponentIdPair, const ManipulatorManagerId managerId) + const size_t vertexIndex, + const ViewportInteraction::MouseInteraction& interaction, + const AZ::EntityComponentIdPair& entityComponentIdPair, + const ManipulatorManagerId managerId) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); Vertex vertex; bool found = false; AZ::FixedVerticesRequestBus::EventResult( - found, GetEntityId(), &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertexIndex, vertex); + found, GetEntityId(), &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertexIndex, vertex); if (m_translationManipulator != nullptr && interaction.m_keyboardModifiers.Ctrl()) { // ensure all selection manipulators are enabled when selecting more than one (the first // will have been disabled when only selecting an individual vertex - m_translationManipulator->Process([this, managerId]( - typename IndexedTranslationManipulator::VertexLookup& vertexLookup) - { - m_selectionManipulators[vertexLookup.m_index]->Register(managerId); - }); + m_translationManipulator->Process( + [this, managerId](typename IndexedTranslationManipulator::VertexLookup& vertexLookup) + { + m_selectionManipulators[vertexLookup.m_index]->Register(managerId); + }); // if selection manipulator was selected, find it in the vector of vertices stored in // the translation manipulator and remove it if (m_selectionManipulators[vertexIndex]->Selected()) { - auto it = AZStd::find_if(m_translationManipulator->m_vertices.begin(), m_translationManipulator->m_vertices.end(), + auto it = AZStd::find_if( + m_translationManipulator->m_vertices.begin(), m_translationManipulator->m_vertices.end(), [vertexIndex](const typename IndexedTranslationManipulator::VertexLookup vertexLookup) - { - return vertexIndex == vertexLookup.m_index; - }); + { + return vertexIndex == vertexLookup.m_index; + }); if (it != m_translationManipulator->m_vertices.end()) { @@ -1099,28 +1068,27 @@ namespace AzToolsFramework { // if one does not already exist, or we're not holding shift, create a new translation // manipulator at this vertex - CreateTranslationManipulator( - entityComponentIdPair, managerId, vertex, vertexIndex); + CreateTranslationManipulator(entityComponentIdPair, managerId, vertex, vertexIndex); } } - /// Configure the selection manipulator for fixed editor selection - this configures the view and action - /// of interacting with the selection manipulator. Vertices can just be selected (create a translation - /// manipulator) but not added or removed. + // configure the selection manipulator for fixed editor selection - this configures the view and action + // of interacting with the selection manipulator. Vertices can just be selected (create a translation + // manipulator) but not added or removed. template void EditorVertexSelectionFixed::SetupSelectionManipulator( const AZStd::shared_ptr& selectionManipulator, const AZ::EntityComponentIdPair& entityComponentIdPair, - const ManipulatorManagerId managerId, const size_t vertexIndex) + const ManipulatorManagerId managerId, + const size_t vertexIndex) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); // setup selection manipulator - const AZStd::shared_ptr selectionView = - AzToolsFramework::CreateManipulatorViewSphere(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), - g_defaultManipulatorSphereRadius, [&selectionManipulator] - (const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, - const bool mouseOver, const AZ::Color& defaultColor) + const AZStd::shared_ptr selectionView = AzToolsFramework::CreateManipulatorViewSphere( + AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), g_defaultManipulatorSphereRadius, + [&selectionManipulator]( + const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, const bool mouseOver, const AZ::Color& defaultColor) { if (selectionManipulator->Selected()) { @@ -1128,72 +1096,68 @@ namespace AzToolsFramework } const float opacity[2] = { 0.5f, 1.0f }; - return AZ::Color( - defaultColor.GetR(), defaultColor.GetG(), defaultColor.GetB(), opacity[mouseOver]); + return AZ::Color(defaultColor.GetR(), defaultColor.GetG(), defaultColor.GetB(), opacity[mouseOver]); }); - selectionManipulator->SetViews(ManipulatorViews{selectionView}); + selectionManipulator->SetViews(ManipulatorViews{ selectionView }); - selectionManipulator->InstallLeftMouseUpCallback([ - this, entityComponentIdPair, vertexIndex, managerId]( - const ViewportInteraction::MouseInteraction& interaction) - { - EditorVertexSelectionBase::SelectionManipulatorSelectCallback( - vertexIndex, interaction, entityComponentIdPair, managerId); - }); + selectionManipulator->InstallLeftMouseUpCallback( + [this, entityComponentIdPair, vertexIndex, managerId](const ViewportInteraction::MouseInteraction& interaction) + { + EditorVertexSelectionBase::SelectionManipulatorSelectCallback( + vertexIndex, interaction, entityComponentIdPair, managerId); + }); } - /// Configure the selection manipulator for variable editor selection - this configures the view and action - /// of interacting with the selection manipulator. In this case, hovering the mouse with a modifier key held - /// will indicate removal, and clicking with a modifier key will remove the vertex. + // configure the selection manipulator for variable editor selection - this configures the view and action + // of interacting with the selection manipulator. In this case, hovering the mouse with a modifier key held + // will indicate removal, and clicking with a modifier key will remove the vertex. template void EditorVertexSelectionVariable::SetupSelectionManipulator( const AZStd::shared_ptr& selectionManipulator, const AZ::EntityComponentIdPair& entityComponentIdPair, - const ManipulatorManagerId managerId, const size_t vertexIndex) + const ManipulatorManagerId managerId, + const size_t vertexIndex) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); // setup selection manipulator - const AZStd::shared_ptr manipulatorView = - AzToolsFramework::CreateManipulatorViewSphere(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), - g_defaultManipulatorSphereRadius, [&selectionManipulator] - (const ViewportInteraction::MouseInteraction& mouseInteraction, - const bool mouseOver, const AZ::Color& defaultColor) + const AZStd::shared_ptr manipulatorView = AzToolsFramework::CreateManipulatorViewSphere( + AZ::Color(1.0f, 0.0f, 0.0f, 1.0f), g_defaultManipulatorSphereRadius, + [&selectionManipulator]( + const ViewportInteraction::MouseInteraction& mouseInteraction, const bool mouseOver, const AZ::Color& defaultColor) + { + if (mouseInteraction.m_keyboardModifiers.Alt() && mouseOver) { - if (mouseInteraction.m_keyboardModifiers.Alt() && mouseOver) - { - // indicate removal of manipulator - return AZ::Color(0.5f, 0.5f, 0.5f, 0.5f); - } + // indicate removal of manipulator + return AZ::Color(0.5f, 0.5f, 0.5f, 0.5f); + } - // highlight or not if mouse is over - const float opacity[2] = { 0.5f, 1.0f }; - if (selectionManipulator->Selected()) - { - return AZ::Color(1.0f, 1.0f, 0.0f, opacity[mouseOver]); - } + // highlight or not if mouse is over + const float opacity[2] = { 0.5f, 1.0f }; + if (selectionManipulator->Selected()) + { + return AZ::Color(1.0f, 1.0f, 0.0f, opacity[mouseOver]); + } - return AZ::Color( - defaultColor.GetR(), defaultColor.GetG(), defaultColor.GetB(), opacity[mouseOver]); - }); + return AZ::Color(defaultColor.GetR(), defaultColor.GetG(), defaultColor.GetB(), opacity[mouseOver]); + }); - - selectionManipulator->SetViews(ManipulatorViews{manipulatorView}); + selectionManipulator->SetViews(ManipulatorViews{ manipulatorView }); selectionManipulator->InstallLeftMouseUpCallback( [this, entityComponentIdPair, vertexIndex, managerId](const ViewportInteraction::MouseInteraction& interaction) - { - if (interaction.m_keyboardModifiers.Alt()) { - SafeRemoveVertex(entityComponentIdPair, vertexIndex); - } - else - { - EditorVertexSelectionBase::SelectionManipulatorSelectCallback( - vertexIndex, interaction, entityComponentIdPair, managerId); - } - }); + if (interaction.m_keyboardModifiers.Alt()) + { + SafeRemoveVertex(entityComponentIdPair, vertexIndex); + } + else + { + EditorVertexSelectionBase::SelectionManipulatorSelectCallback( + vertexIndex, interaction, entityComponentIdPair, managerId); + } + }); } template @@ -1240,15 +1204,17 @@ namespace AzToolsFramework template void EditorVertexSelectionFixed::PrepareActions() { - ActionOverride backAction = CreateBackAction("Deselect Vertex", "Deselect current vertex selection", [this]() - { - EditorVertexSelectionBase::ClearSelected(); - }); + ActionOverride backAction = CreateBackAction( + "Deselect Vertex", "Deselect current vertex selection", + [this]() + { + EditorVertexSelectionBase::ClearSelected(); + }); backAction.SetEntityComponentIdPair(EditorVertexSelectionBase::GetEntityComponentIdPair()); - EditorVertexSelectionBase::m_actionOverrides[static_cast( - EditorVertexSelectionBase::State::Translating)] = AZStd::vector { backAction }; + EditorVertexSelectionBase::m_actionOverrides[static_cast(EditorVertexSelectionBase::State::Translating)] = + AZStd::vector{ backAction }; } template @@ -1261,12 +1227,13 @@ namespace AzToolsFramework MidpointCalculator midpointCalculator; // sort in descending order - std::sort(manipulators.rbegin(), manipulators.rend(), + std::sort( + manipulators.rbegin(), manipulators.rend(), [](const typename IndexedTranslationManipulator::VertexLookup& lhs, const typename IndexedTranslationManipulator::VertexLookup& rhs) - { - return lhs.m_index < rhs.m_index; - }); + { + return lhs.m_index < rhs.m_index; + }); // iterate over current selection for (size_t manipulatorIndex = 0; manipulatorIndex < manipulators.size(); ++manipulatorIndex) @@ -1313,8 +1280,7 @@ namespace AzToolsFramework // create translation manipulator for duplicated vertices at new position EditorVertexSelectionBase::CreateTranslationManipulator( - EditorVertexSelectionBase::GetEntityComponentIdPair(), - EditorVertexSelectionBase::GetManipulatorManagerId(), + EditorVertexSelectionBase::GetEntityComponentIdPair(), EditorVertexSelectionBase::GetManipulatorManagerId(), localCenterPosition, vertices[0].m_index); // clear all selection manipulators to default unselected state @@ -1337,47 +1303,46 @@ namespace AzToolsFramework template void EditorVertexSelectionVariable::PrepareActions() { - ActionOverride deleteAction = CreateDeleteAction(s_deleteVerticesTitle, s_duplicateVerticesDesc, [this]() - { - DestroySelected(); - }); + ActionOverride deleteAction = CreateDeleteAction( + s_deleteVerticesTitle, s_duplicateVerticesDesc, + [this]() + { + DestroySelected(); + }); const AZ::EntityComponentIdPair entityComponentIdPair( - EditorVertexSelectionBase::GetEntityId(), - EditorVertexSelectionBase::GetComponentId()); + EditorVertexSelectionBase::GetEntityId(), EditorVertexSelectionBase::GetComponentId()); // note: important to register which entity/component id pair this action is associated with deleteAction.SetEntityComponentIdPair(entityComponentIdPair); - ActionOverride deselectAction = CreateBackAction(s_deselectVerticesTitle, s_deselectVerticesDesc, [this]() - { - EditorVertexSelectionBase::ClearSelected(); - }); + ActionOverride deselectAction = CreateBackAction( + s_deselectVerticesTitle, s_deselectVerticesDesc, + [this]() + { + EditorVertexSelectionBase::ClearSelected(); + }); // note: important to register which entity/component id pair this action is associated with deselectAction.SetEntityComponentIdPair(entityComponentIdPair); EditorVertexSelectionBase::m_actionOverrides[static_cast(EditorVertexSelectionBase::State::Translating)] = - AZStd::vector - { - ActionOverride() - .SetUri(AzToolsFramework::s_duplicateAction) - .SetKeySequence(QKeySequence(Qt::CTRL + Qt::Key_D)) - .SetTitle(s_duplicateVerticesTitle) - .SetTip(s_duplicateVerticesDesc) - .SetCallback([this]() - { - DuplicateSelected(); - }) - .SetEntityComponentIdPair(entityComponentIdPair), - deleteAction, - deselectAction - }; + AZStd::vector{ ActionOverride() + .SetUri(AzToolsFramework::s_duplicateAction) + .SetKeySequence(QKeySequence(Qt::CTRL + Qt::Key_D)) + .SetTitle(s_duplicateVerticesTitle) + .SetTip(s_duplicateVerticesDesc) + .SetCallback( + [this]() + { + DuplicateSelected(); + }) + .SetEntityComponentIdPair(entityComponentIdPair), + deleteAction, deselectAction }; } template - void InsertVertexAfter( - const AZ::EntityComponentIdPair& entityComponentIdPair, const size_t vertexIndex, const Vertex& localPosition) + void InsertVertexAfter(const AZ::EntityComponentIdPair& entityComponentIdPair, const size_t vertexIndex, const Vertex& localPosition) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -1389,15 +1354,13 @@ namespace AzToolsFramework if (insertPosition >= size) { AZ::VariableVerticesRequestBus::Event( - entityComponentIdPair.GetEntityId(), &AZ::VariableVerticesRequestBus::Handler::AddVertex, - localPosition); + entityComponentIdPair.GetEntityId(), &AZ::VariableVerticesRequestBus::Handler::AddVertex, localPosition); } else { bool updated = false; AZ::VariableVerticesRequestBus::EventResult( - updated, entityComponentIdPair.GetEntityId(), - &AZ::VariableVerticesRequestBus::Handler::InsertVertex, + updated, entityComponentIdPair.GetEntityId(), &AZ::VariableVerticesRequestBus::Handler::InsertVertex, insertPosition, localPosition); } @@ -1409,21 +1372,16 @@ namespace AzToolsFramework { bool removed = false; AZ::VariableVerticesRequestBus::EventResult( - removed, entityComponentIdPair.GetEntityId(), - &AZ::VariableVerticesRequestBus::Handler::RemoveVertex, vertexIndex); + removed, entityComponentIdPair.GetEntityId(), &AZ::VariableVerticesRequestBus::Handler::RemoveVertex, vertexIndex); RefreshUiAfterAddRemove(entityComponentIdPair); } // explicit instantiations - template void InsertVertexAfter( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t, const AZ::Vector2&); - template void InsertVertexAfter( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t, const AZ::Vector3&); - template void SafeRemoveVertex( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); - template void SafeRemoveVertex( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); + template void InsertVertexAfter(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t, const AZ::Vector2&); + template void InsertVertexAfter(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t, const AZ::Vector3&); + template void SafeRemoveVertex(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); + template void SafeRemoveVertex(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); AZ_CLASS_ALLOCATOR_IMPL_TEMPLATE(EditorVertexSelectionFixed, AZ::SystemAllocator, 0) AZ_CLASS_ALLOCATOR_IMPL_TEMPLATE(EditorVertexSelectionFixed, AZ::SystemAllocator, 0) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.h index 4d1c3ce43f..0036ea42d4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/EditorVertexSelection.h @@ -1,22 +1,22 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once #include #include #include -#include #include +#include #include #include #include @@ -24,37 +24,74 @@ namespace AzToolsFramework { - /// Concrete implementation of AZ::VariableVertices backed by an AZ::VertexContainer. + //! Concrete implementation of AZ::VariableVertices backed by an AZ::VertexContainer. template - class VariableVerticesVertexContainer - : public AZ::VariableVertices + class VariableVerticesVertexContainer : public AZ::VariableVertices { public: explicit VariableVerticesVertexContainer(AZ::VertexContainer& vertexContainer) - : m_vertexContainer(vertexContainer) {} + : m_vertexContainer(vertexContainer) + { + } - bool GetVertex(size_t index, Vertex& vertex) const override { return m_vertexContainer.GetVertex(index, vertex); } - bool UpdateVertex(size_t index, const Vertex& vertex) override { return m_vertexContainer.UpdateVertex(index, vertex); }; - void AddVertex(const Vertex& vertex) override { m_vertexContainer.AddVertex(vertex); } - bool InsertVertex(size_t index, const Vertex& vertex) override { return m_vertexContainer.InsertVertex(index, vertex); } - bool RemoveVertex(size_t index) override { return m_vertexContainer.RemoveVertex(index); } - void SetVertices(const AZStd::vector& vertices) override { m_vertexContainer.SetVertices(vertices); }; - void ClearVertices() override { m_vertexContainer.Clear(); } - size_t Size() const override { return m_vertexContainer.Size(); } - bool Empty() const override { return m_vertexContainer.Empty(); } + bool GetVertex(size_t index, Vertex& vertex) const override + { + return m_vertexContainer.GetVertex(index, vertex); + } + + bool UpdateVertex(size_t index, const Vertex& vertex) override + { + return m_vertexContainer.UpdateVertex(index, vertex); + }; + + void AddVertex(const Vertex& vertex) override + { + m_vertexContainer.AddVertex(vertex); + } + + bool InsertVertex(size_t index, const Vertex& vertex) override + { + return m_vertexContainer.InsertVertex(index, vertex); + } + + bool RemoveVertex(size_t index) override + { + return m_vertexContainer.RemoveVertex(index); + } + + void SetVertices(const AZStd::vector& vertices) override + { + m_vertexContainer.SetVertices(vertices); + }; + + void ClearVertices() override + { + m_vertexContainer.Clear(); + } + + size_t Size() const override + { + return m_vertexContainer.Size(); + } + + bool Empty() const override + { + return m_vertexContainer.Empty(); + } private: AZ::VertexContainer& m_vertexContainer; }; - /// Concrete implementation of AZ::FixedVertices backed by an AZStd::array. + //! Concrete implementation of AZ::FixedVertices backed by an AZStd::array. template - class FixedVerticesArray - : public AZ::FixedVertices + class FixedVerticesArray : public AZ::FixedVertices { public: explicit FixedVerticesArray(AZStd::array& array) - : m_array(array) {} + : m_array(array) + { + } bool GetVertex(size_t index, Vertex& vertex) const override { @@ -72,22 +109,26 @@ namespace AzToolsFramework if (index < m_array.size()) { m_array[index] = vertex; - return true;; + return true; + ; } return false; } - size_t Size() const override { return m_array.size(); } + size_t Size() const override + { + return m_array.size(); + } private: AZStd::array& m_array; }; - /// EditorVertexSelection provides an interface for a collection of manipulators to expose - /// editing of vertices in a container/collection. EditorVertexSelection is templated on the - /// type of Vertex (Vector2/Vector3) stored in the container. - /// EditorVertexSelectionBase provides common behavior shared across Fixed and Variable selections. + //! EditorVertexSelection provides an interface for a collection of manipulators to expose + //! editing of vertices in a container/collection. EditorVertexSelection is templated on the + //! type of Vertex (Vector2/Vector3) stored in the container. + //! EditorVertexSelectionBase provides common behavior shared across Fixed and Variable selections. template class EditorVertexSelectionBase : private AzFramework::EntityDebugDisplayEventBus::Handler @@ -99,89 +140,110 @@ namespace AzToolsFramework EditorVertexSelectionBase& operator=(EditorVertexSelectionBase&&) = default; virtual ~EditorVertexSelectionBase() = default; - /// Setup and configure the EditorVertexSelection for operation. + //! Setup and configure the EditorVertexSelection for operation. void Create( - const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId, + const AZ::EntityComponentIdPair& entityComponentIdPair, + ManipulatorManagerId managerId, AZStd::unique_ptr hoverSelection, TranslationManipulators::Dimensions dimensions, TranslationManipulatorConfiguratorFn translationManipulatorConfigurator); - /// Create a translation manipulator for a given vertex. + //! Create a translation manipulator for a given vertex. void CreateTranslationManipulator( - const AZ::EntityComponentIdPair& entityComponentIdPair, - ManipulatorManagerId managerId, const Vertex& vertex, size_t index); + const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId, const Vertex& vertex, size_t index); - /// Destroy all manipulators associated with the vertex selection. + //! Destroy all manipulators associated with the vertex selection. void Destroy(); - /// Set custom callback for when vertex positions are updated. + //! Set custom callback for when vertex positions are updated. void SetVertexPositionsUpdatedCallback(const AZStd::function& callback); - /// Update manipulators based on local changes to vertex positions. + //! Update manipulators based on local changes to vertex positions. void RefreshLocal(); - /// Update the translation manipulator to be correctly positioned based - /// on the current selection (recenter it). + //! Update the translation manipulator to be correctly positioned based + //! on the current selection (recenter it). void RefreshTranslationManipulator(); - /// Update manipulators based on changes to the entity's transform and non-uniform scale. + //! Update manipulators based on changes to the entity's transform and non-uniform scale. void RefreshSpace(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()); - /// Set bounds dirty (need recalculating) for all owned manipulators (selection, translation, hover). + //! Set bounds dirty (need recalculating) for all owned manipulators (selection, translation, hover). void SetBoundsDirty(); - /// How should the EditorVertexSelection respond to mouse input. - virtual bool HandleMouse( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction); + //! How should the EditorVertexSelection respond to mouse input. + virtual bool HandleMouse(const ViewportInteraction::MouseInteractionEvent& mouseInteraction); - /// Snap the selected vertices to the terrain. - /// Note: With a multi-selection the manipulator will be translated to the picked - /// terrain position with all verts moved relative to it. - void SnapVerticesToTerrain( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction); + //! Snap the selected vertices to the terrain. + //! Note: With a multi-selection the manipulator will be translated to the picked + //! terrain position with all vertices moved relative to it. + void SnapVerticesToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction); - /// The Actions provided by the EditorVertexSelection while it is active. - /// e.g. Vertex deletion, duplication etc. + //! The Actions provided by the EditorVertexSelection while it is active. + //! e.g. Vertex deletion, duplication etc. AZStd::vector ActionOverrides() const; - /// Let the EditorVertexSelection know a batch movement is about to begin so it - /// can avoid certain unnecessary updates. + //! Let the EditorVertexSelection know a batch movement is about to begin so it + //! can avoid certain unnecessary updates. void BeginBatchMovement(); - /// Let the EditorVertexSelection know a batch movement has ended so it can return - /// to its normal state. + //! Let the EditorVertexSelection know a batch movement has ended so it can return + //! to its normal state. void EndBatchMovement(); - /// Set the position of the TranslationManipulators (if active). + //! Set the position of the TranslationManipulators (if active). void SetSelectedPosition(const AZ::Vector3& localPosition); - AZ::EntityId GetEntityId() const { return m_entityComponentIdPair.GetEntityId(); } + AZ::EntityId GetEntityId() const + { + return m_entityComponentIdPair.GetEntityId(); + } protected: - /// Internal interface for EditorVertexSelection. + //! Internal interface for EditorVertexSelection. virtual void SetupSelectionManipulator( const AZStd::shared_ptr& selectionManipulator, const AZ::EntityComponentIdPair& entityComponentIdPair, - ManipulatorManagerId managerId, size_t index) = 0; + ManipulatorManagerId managerId, + size_t index) = 0; virtual void PrepareActions() = 0; - /// Default behavior when clicking on a selection manipulator (representing a vertex). + //! Default behavior when clicking on a selection manipulator (representing a vertex). void SelectionManipulatorSelectCallback( - size_t index, const ViewportInteraction::MouseInteraction& interaction, - const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId); + size_t index, + const ViewportInteraction::MouseInteraction& interaction, + const AZ::EntityComponentIdPair& entityComponentIdPair, + ManipulatorManagerId managerId); - /// Destroy the translation manipulator and deselect all vertices. + //! Destroy the translation manipulator and deselect all vertices. void ClearSelected(); - AZ::ComponentId GetComponentId() const { return m_entityComponentIdPair.GetComponentId(); } - const AZ::EntityComponentIdPair& GetEntityComponentIdPair() const { return m_entityComponentIdPair; } - ManipulatorManagerId GetManipulatorManagerId() const { return m_manipulatorManagerId; } + AZ::ComponentId GetComponentId() const + { + return m_entityComponentIdPair.GetComponentId(); + } - /// Is the translation vertex manipulator in 2D or 3D. - TranslationManipulators::Dimensions Dimensions() const { return m_dimensions; } + const AZ::EntityComponentIdPair& GetEntityComponentIdPair() const + { + return m_entityComponentIdPair; + } - /// How to configure the translation manipulator (view and axes). - TranslationManipulatorConfiguratorFn ConfiguratorFn() const { return m_manipulatorConfiguratorFn; } + ManipulatorManagerId GetManipulatorManagerId() const + { + return m_manipulatorManagerId; + } - /// The state we are in when editing vertices. + //! Is the translation vertex manipulator in 2D or 3D. + TranslationManipulators::Dimensions Dimensions() const + { + return m_dimensions; + } + + //! How to configure the translation manipulator (view and axes). + TranslationManipulatorConfiguratorFn ConfiguratorFn() const + { + return m_manipulatorConfiguratorFn; + } + + //! The state we are in when editing vertices. enum class State { Selecting, @@ -190,23 +252,22 @@ namespace AzToolsFramework void SetState(State state); - AZStd::unique_ptr m_hoverSelection = nullptr; ///< Interface to hover selection, representing bounds that can be selected. - AZStd::shared_ptr> m_translationManipulator = nullptr; ///< Manipulator when vertex is selected to translate it. - AZStd::vector> m_selectionManipulators; ///< Manipulators for each vertex when entity is selected. - AZStd::array, 2> m_actionOverrides; ///< Available actions corresponding to each mode. + AZStd::unique_ptr m_hoverSelection = + nullptr; //!< Interface to hover selection, representing bounds that can be selected. + AZStd::shared_ptr> m_translationManipulator = + nullptr; //!< Manipulator when vertex is selected to translate it. + AZStd::vector> + m_selectionManipulators; //!< Manipulators for each vertex when entity is selected. + AZStd::array, 2> m_actionOverrides; //!< Available actions corresponding to each mode. private: // AzFramework::EntityDebugDisplayEventBus - void DisplayEntityViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; // AzFramework::ViewportDebugDisplayEventBus - void DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + void DisplayViewport2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; - /// Set selected manipulator and vertices position from offset from starting position when pressed. + //! Set selected manipulator and vertices position from offset from starting position when pressed. void UpdateManipulatorsAndVerticesFromOffset( IndexedTranslationManipulator& translationManipulator, const AZ::Vector3& localManipulatorStartPosition, @@ -217,23 +278,24 @@ namespace AzToolsFramework template::value>::type* = nullptr> void UpdateManipulatorSpace(const AzFramework::ViewportInfo& viewportInfo) const; - EditorBoxSelect m_editorBoxSelect; ///< Provide box select support for vertex selection. - AZ::EntityComponentIdPair m_entityComponentIdPair; ///< Id of the Entity and Component this editor vertex selection was created on. - ManipulatorManagerId m_manipulatorManagerId; ///< Id of the manager manipulators created from this type will be associated with. - TranslationManipulators::Dimensions m_dimensions = TranslationManipulators::Dimensions::Three; ///< The dimensions this vertex selection was created with. - TranslationManipulatorConfiguratorFn m_manipulatorConfiguratorFn = nullptr; ///< Function pointer set on Create to decide look and functionality of translation manipulator. - AZStd::function m_onVertexPositionsUpdated = nullptr; ///< Callback for when vertex positions are changed. - State m_state = State::Selecting; ///< Different states VertexSelection can be in. - bool m_worldSpace = false; ///< Are the manipulators being used in local or world space. - bool m_batchMovementInProgress = false; ///< If a batch movement operation is in progress we do not want to - ///< refresh the VertexSelection during it for performance reasons. + EditorBoxSelect m_editorBoxSelect; //!< Provide box select support for vertex selection. + AZ::EntityComponentIdPair m_entityComponentIdPair; //!< Id of the Entity and Component this editor vertex selection was created on. + ManipulatorManagerId m_manipulatorManagerId; //!< Id of the manager manipulators created from this type will be associated with. + TranslationManipulators::Dimensions m_dimensions = + TranslationManipulators::Dimensions::Three; //!< The dimensions this vertex selection was created with. + TranslationManipulatorConfiguratorFn m_manipulatorConfiguratorFn = + nullptr; //!< Function pointer set on Create to decide look and functionality of translation manipulator. + AZStd::function m_onVertexPositionsUpdated = nullptr; //!< Callback for when vertex positions are changed. + State m_state = State::Selecting; //!< Different states VertexSelection can be in. + bool m_worldSpace = false; //!< Are the manipulators being used in local or world space. + bool m_batchMovementInProgress = false; //!< If a batch movement operation is in progress we do not want to + //!< refresh the VertexSelection during it for performance reasons. }; - /// EditorVertexSelectionFixed provides selection and editing for a fixed length number of - /// vertices. New vertices cannot be inserted/added or removed. + //! EditorVertexSelectionFixed provides selection and editing for a fixed length number of + //! vertices. New vertices cannot be inserted/added or removed. template - class EditorVertexSelectionFixed - : public EditorVertexSelectionBase + class EditorVertexSelectionFixed : public EditorVertexSelectionBase { public: AZ_CLASS_ALLOCATOR_DECL @@ -247,15 +309,15 @@ namespace AzToolsFramework void SetupSelectionManipulator( const AZStd::shared_ptr& selectionManipulator, const AZ::EntityComponentIdPair& entityComponentIdPair, - ManipulatorManagerId managerId, size_t index) override; + ManipulatorManagerId managerId, + size_t index) override; void PrepareActions() override; }; - /// EditorVertexSelectionVariable provides selection and editing for a variable length number of - /// vertices. New vertices can be inserted/added or removed from the collection. + //! EditorVertexSelectionVariable provides selection and editing for a variable length number of + //! vertices. New vertices can be inserted/added or removed from the collection. template - class EditorVertexSelectionVariable - : public EditorVertexSelectionBase + class EditorVertexSelectionVariable : public EditorVertexSelectionBase { public: AZ_CLASS_ALLOCATOR_DECL @@ -272,7 +334,8 @@ namespace AzToolsFramework void SetupSelectionManipulator( const AZStd::shared_ptr& selectionManipulator, const AZ::EntityComponentIdPair& entityComponentIdPair, - ManipulatorManagerId managerId, size_t vertIndex) override; + ManipulatorManagerId managerId, + size_t vertIndex) override; //! Presents a warning to the user that vertices will not be deleted. //! @note Allow overriding by derived classes to make this a noop if required. @@ -281,21 +344,18 @@ namespace AzToolsFramework private: void PrepareActions() override; - /// @return The center point of the selected vertices. - Vertex InsertSelectedInPlace( - AZStd::vector::VertexLookup>& manipulators); + //! @return The center point of the selected vertices. + Vertex InsertSelectedInPlace(AZStd::vector::VertexLookup>& manipulators); }; - /// Helper for inserting a vertex in a variable vertices container. + //! Helper for inserting a vertex in a variable vertices container. template - void InsertVertexAfter( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertIndex, const Vertex& localPosition); + void InsertVertexAfter(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertIndex, const Vertex& localPosition); - /// Helper for removing a vertex in a variable vertices container. - /// Remove a vertex from the container and ensure the associated manipulator is unset and - /// property display values are refreshed. + //! Helper for removing a vertex in a variable vertices container. + //! Remove a vertex from the container and ensure the associated manipulator is unset and + //! property display values are refreshed. template - void SafeRemoveVertex( - const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); + void SafeRemoveVertex(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/HoverSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/HoverSelection.h index c5f58f0d56..a389237b2b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/HoverSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/HoverSelection.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -16,10 +16,10 @@ namespace AzToolsFramework { - /// HoverSelection provides an interface for manipulator/s offering selection when - /// the mouse is hovered over a particular bound. This interface is used to represent - /// a Spline manipulator bound, and a series of LineSegment manipulator bounds. - /// This generic interface allows EditorVertexSelection to use either Spline or LineSegment selection. + //! HoverSelection provides an interface for manipulator/s offering selection when + //! the mouse is hovered over a particular bound. This interface is used to represent + //! a Spline manipulator bound, and a series of LineSegment manipulator bounds. + //! This generic interface allows EditorVertexSelection to use either Spline or LineSegment selection. class HoverSelection { public: @@ -33,21 +33,37 @@ namespace AzToolsFramework virtual void SetNonUniformScale(const AZ::Vector3& nonUniformScale) = 0; }; - /// NullHoverSelection is used when vertices cannot be inserted. This serves as a no-op - /// and is used to prevent the need for additional null checks in EditorVertexSelection. - class NullHoverSelection - : public HoverSelection + //! NullHoverSelection is used when vertices cannot be inserted. This serves as a no-op + //! and is used to prevent the need for additional null checks in EditorVertexSelection. + class NullHoverSelection : public HoverSelection { public: NullHoverSelection() = default; NullHoverSelection(const NullHoverSelection&) = delete; NullHoverSelection& operator=(const NullHoverSelection&) = delete; - void Register(ManipulatorManagerId /*managerId*/) override {} - void Unregister() override {} - void SetBoundsDirty() override {} - void Refresh() override {} - void SetSpace(const AZ::Transform& /*worldFromLocal*/) override {} - void SetNonUniformScale([[maybe_unused]] const AZ::Vector3& nonUniformScale) override {} + void Register([[maybe_unused]] ManipulatorManagerId managerId) override + { + } + + void Unregister() override + { + } + + void SetBoundsDirty() override + { + } + + void Refresh() override + { + } + + void SetSpace([[maybe_unused]] const AZ::Transform& worldFromLocal) override + { + } + + void SetNonUniformScale([[maybe_unused]] const AZ::Vector3& nonUniformScale) override + { + } }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.cpp index e26c154be9..12d5f399c3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "LineHoverSelection.h" @@ -22,17 +22,15 @@ namespace AzToolsFramework { - static const AZ::Color s_lineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); + static const AZ::Color LineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); template - static void UpdateLineSegmentPosition( - const size_t vertIndex, const AZ::EntityId entityId, LineSegmentSelectionManipulator& lineSegment) + static void UpdateLineSegmentPosition(const size_t vertIndex, const AZ::EntityId entityId, LineSegmentSelectionManipulator& lineSegment) { Vertex start; bool foundStart = false; AZ::FixedVerticesRequestBus::EventResult( - foundStart, entityId, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - vertIndex, start); + foundStart, entityId, &AZ::FixedVerticesRequestBus::Handler::GetVertex, vertIndex, start); if (foundStart) { @@ -40,14 +38,12 @@ namespace AzToolsFramework } size_t size = 0; - AZ::FixedVerticesRequestBus::EventResult( - size, entityId, &AZ::FixedVerticesRequestBus::Handler::Size); + AZ::FixedVerticesRequestBus::EventResult(size, entityId, &AZ::FixedVerticesRequestBus::Handler::Size); Vertex end; bool foundEnd = false; AZ::FixedVerticesRequestBus::EventResult( - foundEnd, entityId, &AZ::FixedVerticesRequestBus::Handler::GetVertex, - (vertIndex + 1) % size, end); + foundEnd, entityId, &AZ::FixedVerticesRequestBus::Handler::GetVertex, (vertIndex + 1) % size, end); if (foundEnd) { @@ -56,8 +52,7 @@ namespace AzToolsFramework // update the view const float lineWidth = 0.05f; - lineSegment.SetView( - CreateManipulatorViewLineSelect(lineSegment, s_lineSelectManipulatorColor, lineWidth)); + lineSegment.SetView(CreateManipulatorViewLineSelect(lineSegment, LineSelectManipulatorColor, lineWidth)); } template @@ -66,9 +61,8 @@ namespace AzToolsFramework : m_entityId(entityComponentIdPair.GetEntityId()) { // create a line segment manipulator from vertex positions and setup its callback - auto setupLineSegment = [this] ( - const AZ::EntityComponentIdPair& entityComponentIdPair, - const ManipulatorManagerId managerId, const size_t vertIndex) + auto setupLineSegment = + [this](const AZ::EntityComponentIdPair& entityComponentIdPair, const ManipulatorManagerId managerId, const size_t vertIndex) { m_lineSegmentManipulators.push_back(LineSegmentSelectionManipulator::MakeShared()); AZStd::shared_ptr& lineSegmentManipulator = m_lineSegmentManipulators.back(); @@ -81,11 +75,9 @@ namespace AzToolsFramework lineSegmentManipulator->InstallLeftMouseUpCallback( [vertIndex, entityComponentIdPair](const LineSegmentSelectionManipulator::Action& action) - { - InsertVertexAfter( - entityComponentIdPair, vertIndex, - AZ::AdaptVertexIn(action.m_localLineHitPosition)); - }); + { + InsertVertexAfter(entityComponentIdPair, vertIndex, AZ::AdaptVertexIn(action.m_localLineHitPosition)); + }); }; // create all line segment manipulators for the polygon prism (used for selection bounds) @@ -150,8 +142,7 @@ namespace AzToolsFramework void LineSegmentHoverSelection::Refresh() { size_t vertexCount = 0; - AZ::FixedVerticesRequestBus::EventResult( - vertexCount, m_entityId, &AZ::FixedVerticesRequestBus::Handler::Size); + AZ::FixedVerticesRequestBus::EventResult(vertexCount, m_entityId, &AZ::FixedVerticesRequestBus::Handler::Size); // update the start/end positions of all the line segment manipulators to ensure // they stay consistent with the polygon prism shape diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.h index eb5e3991c5..e14930f9ca 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineHoverSelection.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -25,17 +25,14 @@ namespace AzToolsFramework { class LineSegmentSelectionManipulator; - /// LineSegmentHoverSelection is a concrete implementation of HoverSelection wrapping a collection/container - /// of vertices and a list of LineSegmentManipulators. The underlying manipulators are used to control selection - /// by highlighting where on the line a new vertex will be inserted. + //! LineSegmentHoverSelection is a concrete implementation of HoverSelection wrapping a collection/container + //! of vertices and a list of LineSegmentManipulators. The underlying manipulators are used to control selection + //! by highlighting where on the line a new vertex will be inserted. template - class LineSegmentHoverSelection - : public HoverSelection + class LineSegmentHoverSelection : public HoverSelection { public: - explicit LineSegmentHoverSelection( - const AZ::EntityComponentIdPair& entityComponentIdPair, - ManipulatorManagerId managerId); + explicit LineSegmentHoverSelection(const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId); LineSegmentHoverSelection(const LineSegmentHoverSelection&) = delete; LineSegmentHoverSelection& operator=(const LineSegmentHoverSelection&) = delete; ~LineSegmentHoverSelection(); @@ -49,6 +46,6 @@ namespace AzToolsFramework private: AZ::EntityId m_entityId; - AZStd::vector> m_lineSegmentManipulators; ///< Manipulators for each line. + AZStd::vector> m_lineSegmentManipulators; //!< Manipulators for each line. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp index 8874e0dcd9..45f2803818 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "LineSegmentSelectionManipulator.h" @@ -20,15 +20,20 @@ namespace AzToolsFramework { LineSegmentSelectionManipulator::Action CalculateManipulationDataAction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin, - const AZ::Vector3& rayDirection, const float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd) + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const float rayLength, + const AZ::Vector3& localStart, + const AZ::Vector3& localEnd) { AZ::Vector3 worldClosestPositionRay, worldClosestPositionLineSegment; float rayProportion, lineSegmentProportion; AZ::Intersect::ClosestSegmentSegment( - rayOrigin, rayOrigin + rayDirection * rayLength, - worldFromLocal.TransformPoint(nonUniformScale * localStart), worldFromLocal.TransformPoint(nonUniformScale * localEnd), - rayProportion, lineSegmentProportion, worldClosestPositionRay, worldClosestPositionLineSegment); + rayOrigin, rayOrigin + rayDirection * rayLength, worldFromLocal.TransformPoint(nonUniformScale * localStart), + worldFromLocal.TransformPoint(nonUniformScale * localEnd), rayProportion, lineSegmentProportion, worldClosestPositionRay, + worldClosestPositionLineSegment); AZ::Transform worldFromLocalNormalized = worldFromLocal; const AZ::Vector3 scale = worldFromLocalNormalized.ExtractUniformScale() * nonUniformScale; @@ -47,7 +52,9 @@ namespace AzToolsFramework AttachLeftMouseDownImpl(); } - LineSegmentSelectionManipulator::~LineSegmentSelectionManipulator() {} + LineSegmentSelectionManipulator::~LineSegmentSelectionManipulator() + { + } void LineSegmentSelectionManipulator::InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback) { @@ -112,12 +119,9 @@ namespace AzToolsFramework if (mouseInteraction.m_keyboardModifiers.Ctrl() && !mouseInteraction.m_keyboardModifiers.Shift()) { m_manipulatorView->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - TransformUniformScale(GetSpace()), GetNonUniformScale(), - m_localStart, MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay, cameraState, + mouseInteraction); } } @@ -135,4 +139,4 @@ namespace AzToolsFramework { m_manipulatorView->Invalidate(GetManipulatorManagerId()); } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.h index d9e317c378..107a0ccf9f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -20,12 +20,12 @@ namespace AzToolsFramework { class ManipulatorView; - /// A manipulator to expose where on a line a user is moving their mouse. + //! A manipulator to expose where on a line a user is moving their mouse. class LineSegmentSelectionManipulator : public BaseManipulator , public ManipulatorSpace { - /// Private constructor. + //! Private constructor. LineSegmentSelectionManipulator(); public: @@ -37,10 +37,10 @@ namespace AzToolsFramework ~LineSegmentSelectionManipulator(); - /// A Manipulator must only be created and managed through a shared_ptr. + //! A Manipulator must only be created and managed through a shared_ptr. static AZStd::shared_ptr MakeShared(); - /// Mouse action data used by MouseActionCallback. + //! Mouse action data used by MouseActionCallback. struct Action { AZ::Vector3 m_localLineHitPosition; @@ -57,18 +57,31 @@ namespace AzToolsFramework const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; - void SetStart(const AZ::Vector3& startLocal) { m_localStart = startLocal; } - void SetEnd(const AZ::Vector3& endLocal) { m_localEnd = endLocal; } - const AZ::Vector3& GetStart() const { return m_localStart; } - const AZ::Vector3& GetEnd() const { return m_localEnd; } + void SetStart(const AZ::Vector3& startLocal) + { + m_localStart = startLocal; + } + + void SetEnd(const AZ::Vector3& endLocal) + { + m_localEnd = endLocal; + } + + const AZ::Vector3& GetStart() const + { + return m_localStart; + } + + const AZ::Vector3& GetEnd() const + { + return m_localEnd; + } void SetView(AZStd::unique_ptr&& view); private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; @@ -79,12 +92,18 @@ namespace AzToolsFramework MouseActionCallback m_onLeftMouseDownCallback = nullptr; MouseActionCallback m_onLeftMouseUpCallback = nullptr; - ViewportInteraction::KeyboardModifiers m_keyboardModifiers; ///< What modifier keys are pressed when interacting with this manipulator. + ViewportInteraction::KeyboardModifiers + m_keyboardModifiers; //!< What modifier keys are pressed when interacting with this manipulator. - AZStd::unique_ptr m_manipulatorView = nullptr; ///< Look of manipulator. + AZStd::unique_ptr m_manipulatorView = nullptr; //!< Look of manipulator. }; LineSegmentSelectionManipulator::Action CalculateManipulationDataAction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin, - const AZ::Vector3& rayDirection, float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd); + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + float rayLength, + const AZ::Vector3& localStart, + const AZ::Vector3& localEnd); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp index 34ae28bd13..604e74b6f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "LinearManipulator.h" @@ -22,13 +22,16 @@ namespace AzToolsFramework { LinearManipulator::Starter CalculateLinearManipulationDataStart( - const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance, + const LinearManipulator::Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const ViewportInteraction::MouseInteraction& interaction, + const float intersectionDistance, const AzFramework::CameraState& cameraState) { - const ManipulatorInteraction manipulatorInteraction = - BuildManipulatorInteraction( - worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); + const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( + worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis); const AZ::Vector3 rayCrossAxis = manipulatorInteraction.m_localRayDirection.Cross(axis); @@ -47,32 +50,35 @@ namespace AzToolsFramework manipulatorInteraction.m_localRayOrigin + manipulatorInteraction.m_localRayDirection * intersectionDistance; Internal::CalculateRayPlaneIntersectingPoint( - manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, - localIntersectionPoint, startTransition.m_localNormal, start.m_localHitPosition); + manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, + startTransition.m_localNormal, start.m_localHitPosition); start.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; start.m_localPosition = localTransform.GetTranslation(); - start.m_localScale = AZ::Vector3(localTransform.GetUniformScale());; + start.m_localScale = AZ::Vector3(localTransform.GetUniformScale()); + ; start.m_localAxis = axis; // sign to determine which side of the linear axis we pressed // (useful to know when the visual axis flips to face the camera) - start.m_sign = - AZ::GetSign((start.m_localHitPosition - localTransform.GetTranslation()).Dot(axis)); + start.m_sign = AZ::GetSign((start.m_localHitPosition - localTransform.GetTranslation()).Dot(axis)); startTransition.m_screenToWorldScale = 1.0f / CalculateScreenToWorldMultiplier((worldFromLocal * localTransform).GetTranslation(), cameraState); - return {startTransition, start}; + return { startTransition, start }; } LinearManipulator::Action CalculateLinearManipulationDataAction( - const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) + const LinearManipulator::Fixed& fixed, + const LinearManipulator::Starter& starter, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const GridSnapParameters& gridSnapParams, + const ViewportInteraction::MouseInteraction& interaction) { - const ManipulatorInteraction manipulatorInteraction = - BuildManipulatorInteraction( - worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); + const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( + worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const auto& [startTransition, start] = starter; @@ -81,8 +87,8 @@ namespace AzToolsFramework // if an invalid ray intersection is attempted AZ::Vector3 localHitPosition = start.m_localHitPosition; Internal::CalculateRayPlaneIntersectingPoint( - manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, - start.m_localHitPosition, startTransition.m_localNormal, localHitPosition); + manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, start.m_localHitPosition, + startTransition.m_localNormal, localHitPosition); localHitPosition = Internal::TryConstrainHitPositionToView( localHitPosition, start.m_localHitPosition, worldFromLocal.GetInverse(), @@ -103,9 +109,8 @@ namespace AzToolsFramework LinearManipulator::Action action; action.m_fixed = fixed; action.m_start = start; - action.m_current.m_localPositionOffset = snapping - ? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip) - : unsnappedOffset; + action.m_current.m_localPositionOffset = + snapping ? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip) : unsnappedOffset; action.m_current.m_screenPosition = interaction.m_mousePick.m_screenCoordinates; action.m_viewportId = interaction.m_interactionId.m_viewportId; @@ -191,7 +196,8 @@ namespace AzToolsFramework // note: m_localTransform must not be made uniform as it may contain a local scale we want to snap m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction( - m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction)); + m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, + interaction)); } } @@ -202,16 +208,14 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& mouseInteraction) { const AZ::Transform localTransform = m_useVisualsOverride - ? AZ::Transform::CreateFromQuaternionAndTranslation( - m_visualOrientationOverride, GetLocalPosition()) + ? AZ::Transform::CreateFromQuaternionAndTranslation(m_visualOrientationOverride, GetLocalPosition()) : GetLocalTransform(); if (cl_manipulatorDrawDebug) { if (PerformingAction()) { - const GridSnapParameters gridSnapParams = - GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); + const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId); const auto action = CalculateLinearManipulationDataAction( m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, @@ -219,9 +223,10 @@ namespace AzToolsFramework // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( - debugDisplay, TransformUniformScale(GetSpace()) * - AZ::Transform::CreateTranslation( - action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localPositionOffset)); + debugDisplay, + TransformUniformScale(GetSpace()) * + AZ::Transform::CreateTranslation( + action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localPositionOffset)); } AZ::Transform combined = GetLocalTransform(); @@ -229,8 +234,7 @@ namespace AzToolsFramework combined = GetSpace() * combined; DrawTransformAxes(debugDisplay, combined); - DrawAxis( - debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, m_fixed.m_axis)); + DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, m_fixed.m_axis)); } for (auto& view : m_manipulatorViews) @@ -238,12 +242,9 @@ namespace AzToolsFramework auto nonUniformScale = GetNonUniformScale(); view->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - ApplySpace(localTransform), GetNonUniformScale(), - AZ::Vector3::CreateZero(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState, + mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h index c3d43a2535..240d4c7b9b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,13 +22,13 @@ namespace AzToolsFramework { struct GridSnapParameters; - /// LinearManipulator serves as a visual tool for users to modify values - /// in one dimension on an axis defined in 3D space. + //! LinearManipulator serves as a visual tool for users to modify values + //! in one dimension on an axis defined in 3D space. class LinearManipulator : public BaseManipulator , public ManipulatorSpaceWithLocalTransform { - /// Private constructor. + //! Private constructor. explicit LinearManipulator(const AZ::Transform& worldFromLocal); public: @@ -41,68 +41,80 @@ namespace AzToolsFramework ~LinearManipulator() = default; - /// A Manipulator must only be created and managed through a shared_ptr. - /// @note worldFromLocal should not contain scale. + //! A Manipulator must only be created and managed through a shared_ptr. + //! @note worldFromLocal should not contain scale. static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal); - /// Unchanging data set once for the linear manipulator. + //! Unchanging data set once for the linear manipulator. struct Fixed { - AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); ///< The axis the manipulator will move along. + AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); //!< The axis the manipulator will move along. }; - /// Data passed between the initial press and first movement of the linear manipulator. + //! Data passed between the initial press and first movement of the linear manipulator. struct StartTransition { - /// The normal in local space of the manipulator when the mouse down event happens. + //! The normal in local space of the manipulator when the mouse down event happens. AZ::Vector3 m_localNormal; - /// Used to scale movement based on camera distance if we want screen space instead - /// of world space displacement. + //! Used to scale movement based on camera distance if we want screen space instead + //! of world space displacement. float m_screenToWorldScale; }; - /// The state of the manipulator at the start of an interaction. + //! The state of the manipulator at the start of an interaction. struct Start { - AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. - AZ::Vector3 m_localScale; ///< The current scale of the manipulator in local space. - AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. - AZ::Vector3 m_localAxis; ///< The axis in the local space of the manipulator itself. - float m_sign; ///< Used to determine which side of the axis we clicked on in case it's flipped to face the camera. - AzFramework::ScreenPoint m_screenPosition; ///< The initial position in screen space of the manipulator. + AZ::Vector3 m_localPosition; //!< The current position of the manipulator in local space. + AZ::Vector3 m_localScale; //!< The current scale of the manipulator in local space. + AZ::Vector3 m_localHitPosition; //!< The intersection point in local space between the ray and the manipulator when the mouse + //!< down event happens. + AZ::Vector3 m_localAxis; //!< The axis in the local space of the manipulator itself. + float m_sign; //!< Used to determine which side of the axis we clicked on in case it's flipped to face the camera. + AzFramework::ScreenPoint m_screenPosition; //!< The initial position in screen space of the manipulator. }; - /// The state of the manipulator during an interaction. + //! The state of the manipulator during an interaction. struct Current { - AZ::Vector3 m_localPositionOffset; ///< The current offset of the manipulator from its starting position in local space. - AZ::Vector3 m_localScaleOffset; ///< The current offset of the manipulator from its starting scale in local space. - AzFramework::ScreenPoint m_screenPosition; ///< The current position in screen space of the manipulator. + AZ::Vector3 m_localPositionOffset; //!< The current offset of the manipulator from its starting position in local space. + AZ::Vector3 m_localScaleOffset; //!< The current offset of the manipulator from its starting scale in local space. + AzFramework::ScreenPoint m_screenPosition; //!< The current position in screen space of the manipulator. }; - /// Mouse action data used by MouseActionCallback (wraps Fixed, Start and Current manipulator state). + //! Mouse action data used by MouseActionCallback (wraps Fixed, Start and Current manipulator state). struct Action { Fixed m_fixed; Start m_start; Current m_current; ViewportInteraction::KeyboardModifiers m_modifiers; - int m_viewportId; ///< The id of the viewport this manipulator is being used in. - AZ::Vector3 LocalScale() const { return m_start.m_localScale + m_current.m_localScaleOffset; } - AZ::Vector3 LocalScaleOffset() const { return m_current.m_localScaleOffset; } - AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; } - AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; } + int m_viewportId; //!< The id of the viewport this manipulator is being used in. + AZ::Vector3 LocalScale() const + { + return m_start.m_localScale + m_current.m_localScaleOffset; + } + AZ::Vector3 LocalScaleOffset() const + { + return m_current.m_localScaleOffset; + } + AZ::Vector3 LocalPosition() const + { + return m_start.m_localPosition + m_current.m_localPositionOffset; + } + AZ::Vector3 LocalPositionOffset() const + { + return m_current.m_localPositionOffset; + } AZ::Vector2 ScreenOffset() const { - return AzFramework::Vector2FromScreenVector( - m_current.m_screenPosition - m_start.m_screenPosition); + return AzFramework::Vector2FromScreenVector(m_current.m_screenPosition - m_start.m_screenPosition); } }; - /// This is the function signature of callbacks that will be invoked whenever a manipulator - /// is clicked on or dragged. + //! This is the function signature of callbacks that will be invoked whenever a manipulator + //! is clicked on or dragged. using MouseActionCallback = AZStd::function; - /// Tuple of StartTransition (initial mouse down to mouse move) and Start state. + //! Tuple of StartTransition (initial mouse down to mouse move) and Start state. using Starter = AZStd::tuple; void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback); @@ -116,7 +128,10 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& mouseInteraction) override; void SetAxis(const AZ::Vector3& axis); - const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; } + const AZ::Vector3& GetAxis() const + { + return m_fixed.m_axis; + } template void SetViews(Views&& views) @@ -135,12 +150,9 @@ namespace AzToolsFramework } private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; - void OnMouseMoveImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; + void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; @@ -155,16 +167,24 @@ namespace AzToolsFramework MouseActionCallback m_onLeftMouseUpCallback = nullptr; MouseActionCallback m_onMouseMoveCallback = nullptr; - ManipulatorViews m_manipulatorViews; ///< Look of manipulator. + ManipulatorViews m_manipulatorViews; //!< Look of manipulator. }; LinearManipulator::Starter CalculateLinearManipulationDataStart( - const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance, + const LinearManipulator::Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const ViewportInteraction::MouseInteraction& interaction, + float intersectionDistance, const AzFramework::CameraState& cameraState); LinearManipulator::Action CalculateLinearManipulationDataAction( - const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter, - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction); + const LinearManipulator::Fixed& fixed, + const LinearManipulator::Starter& starter, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const GridSnapParameters& gridSnapParams, + const ViewportInteraction::MouseInteraction& interaction); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorBus.h index 7768368d6b..a79a14abc2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorBus.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -26,56 +26,55 @@ namespace AzToolsFramework using ManipulatorManagerId = IdType; static const ManipulatorManagerId InvalidManipulatorManagerId = ManipulatorManagerId(0); - /// EBus interface used to send requests to ManipulatorManager. - class ManipulatorManagerRequests - : public AZ::EBusTraits + //! EBus interface used to send requests to ManipulatorManager. + class ManipulatorManagerRequests : public AZ::EBusTraits { public: - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; /**< We can have multiple manipulator managers. - In the case where there are multiple viewports, each displaying - a different set of entities, a different manipulator manager is required - to provide a different collision space for each viewport so that mouse - hit detection can be handled properly. */ + //! We can have multiple manipulator managers. + //! In the case where there are multiple viewports, each displaying + //! a different set of entities, a different manipulator manager is required + //! to provide a different collision space for each viewport so that mouse + //! hit detection can be handled properly. + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; using BusIdType = ManipulatorManagerId; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; virtual ~ManipulatorManagerRequests() = default; - /// Register a manipulator with the Manipulator Manager. - /// @param manipulator The manipulator parameter is passed as a shared_ptr so - /// that the system responsible for managing manipulators can maintain ownership - /// of the manipulator even if is destroyed while in use. + //! Register a manipulator with the Manipulator Manager. + //! @param manipulator The manipulator parameter is passed as a shared_ptr so + //! that the system responsible for managing manipulators can maintain ownership + //! of the manipulator even if is destroyed while in use. virtual void RegisterManipulator(AZStd::shared_ptr manipulator) = 0; - /// Unregister a manipulator from the Manipulator Manager. - /// After unregistering the manipulator, it will be excluded from mouse hit detection - /// and will not receive any mouse action events. The Manipulator Manager will also - /// relinquish ownership of the manipulator. + //! Unregister a manipulator from the Manipulator Manager. + //! After unregistering the manipulator, it will be excluded from mouse hit detection + //! and will not receive any mouse action events. The Manipulator Manager will also + //! relinquish ownership of the manipulator. virtual void UnregisterManipulator(BaseManipulator* manipulator) = 0; - /// Delete a manipulator bound. + //! Delete a manipulator bound. virtual void DeleteManipulatorBound(Picking::RegisteredBoundId boundId) = 0; - /// Mark the bound of a manipulator dirty so it's excluded from mouse hit detection. - /// This should be called whenever a manipulator is moved. + //! Mark the bound of a manipulator dirty so it's excluded from mouse hit detection. + //! This should be called whenever a manipulator is moved. virtual void SetBoundDirty(Picking::RegisteredBoundId boundId) = 0; - /// Returns true if the manipulator manager is currently interacting, otherwise false. + //! Returns true if the manipulator manager is currently interacting, otherwise false. virtual bool Interacting() const = 0; - /// Update the bound for a manipulator. - /// If \ref boundId hasn't been registered before or it's invalid, a new bound is created and set using \ref boundShapeData - /// @param manipulatorId The id of the manipulator whose bound needs to update. - /// @param boundId The id of the bound that needs to update. - /// @param boundShapeData The pointer to the new bound shape data. - /// @return If \ref boundId has been registered return the same id, otherwise create a new bound and return its id. + //! Update the bound for a manipulator. + //! If \ref boundId hasn't been registered before or it's invalid, a new bound is created and set using \ref boundShapeData. + //! @param manipulatorId The id of the manipulator whose bound needs to update. + //! @param boundId The id of the bound that needs to update. + //! @param boundShapeData The pointer to the new bound shape data. + //! @return If \ref boundId has been registered return the same id, otherwise create a new bound and return its id. virtual Picking::RegisteredBoundId UpdateBound( - ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, - const Picking::BoundRequestShapeBase& boundShapeData) = 0; + ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData) = 0; }; - /// Type to inherit to implement ManipulatorManagerRequests. + //! Type to inherit to implement ManipulatorManagerRequests. using ManipulatorManagerRequestBus = AZ::EBus; -}//namespace AzToolsFramework +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp index c856c5f9a8..3a6a2487c3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.cpp @@ -1,17 +1,17 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ -#include "BaseManipulator.h" #include "ManipulatorManager.h" +#include "BaseManipulator.h" #include #include @@ -51,7 +51,8 @@ namespace AzToolsFramework if (manipulator->Registered()) { - AZ_Assert(manipulator->GetManipulatorManagerId() == m_manipulatorManagerId, + AZ_Assert( + manipulator->GetManipulatorManagerId() == m_manipulatorManagerId, "This manipulator was registered with a different manipulator manager!"); return; } @@ -75,8 +76,7 @@ namespace AzToolsFramework } Picking::RegisteredBoundId ManipulatorManager::UpdateBound( - const ManipulatorId manipulatorId, const Picking::RegisteredBoundId boundId, - const Picking::BoundRequestShapeBase& boundShapeData) + const ManipulatorId manipulatorId, const Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -99,8 +99,7 @@ namespace AzToolsFramework AZ_Assert(boundItr->second == manipulatorId, "Manipulator and its bounds are out of synchronization!"); } - const Picking::RegisteredBoundId newBoundId = - m_boundManager.UpdateOrRegisterBound(boundShapeData, boundId); + const Picking::RegisteredBoundId newBoundId = m_boundManager.UpdateOrRegisterBound(boundShapeData, boundId); if (newBoundId != boundId) { @@ -142,13 +141,6 @@ namespace AzToolsFramework } } - void ManipulatorManager::CheckModifierKeysChanged( - [[maybe_unused]] const ViewportInteraction::KeyboardModifiers keyboardModifiers, - const ViewportInteraction::MousePick& mousePick) - { - RefreshMouseOverState(mousePick); - } - void ManipulatorManager::DrawManipulators( AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, @@ -181,7 +173,8 @@ namespace AzToolsFramework if (found != m_boundIdToManipulatorIdMap.end()) { const auto manipulatorFound = m_manipulatorIdToPtrMap.find(found->second); - AZ_Assert(manipulatorFound != m_manipulatorIdToPtrMap.end(), + AZ_Assert( + manipulatorFound != m_manipulatorIdToPtrMap.end(), "Found a bound without a corresponding Manipulator, " "it's likely a bound was not cleaned up correctly"); rayIntersectionDistance = hitItr.second; @@ -194,10 +187,9 @@ namespace AzToolsFramework bool ManipulatorManager::ConsumeViewportMousePress(const ViewportInteraction::MouseInteraction& interaction) { - if (auto pickedManipulator = PickManipulator(interaction.m_mousePick); - pickedManipulator.has_value()) + if (auto pickedManipulator = PickManipulator(interaction.m_mousePick); pickedManipulator.has_value()) { - auto[manipulator, intersectionDistance] = pickedManipulator.value(); + auto [manipulator, intersectionDistance] = pickedManipulator.value(); if (interaction.m_mouseButtons.Left()) { @@ -249,24 +241,19 @@ namespace AzToolsFramework const ViewportInteraction::MousePick& mousePick) { float intersectionDistance = 0.0f; - const AZStd::shared_ptr pickedManipulator = PerformRaycast( - mousePick.m_rayOrigin, mousePick.m_rayDirection, intersectionDistance); + const AZStd::shared_ptr pickedManipulator = + PerformRaycast(mousePick.m_rayOrigin, mousePick.m_rayDirection, intersectionDistance); - return pickedManipulator.get() != nullptr - ? AZStd::make_optional(AZStd::make_tuple(pickedManipulator, intersectionDistance)) - : AZStd::nullopt; + return pickedManipulator.get() != nullptr ? AZStd::make_optional(AZStd::make_tuple(pickedManipulator, intersectionDistance)) + : AZStd::nullopt; } - ManipulatorManager::PickedManipulatorId ManipulatorManager::PickManipulatorId( - const ViewportInteraction::MousePick& mousePick) + ManipulatorManager::PickedManipulatorId ManipulatorManager::PickManipulatorId(const ViewportInteraction::MousePick& mousePick) { - auto [manipulator, intersectionDistance] = - PickManipulator(mousePick).value_or(PickedManipulator(nullptr, 0.0f)); - const ManipulatorId pickedManipulatorId = manipulator - ? manipulator->GetManipulatorId() - : InvalidManipulatorId; + auto [manipulator, intersectionDistance] = PickManipulator(mousePick).value_or(PickedManipulator(nullptr, 0.0f)); + const ManipulatorId pickedManipulatorId = manipulator ? manipulator->GetManipulatorId() : InvalidManipulatorId; - return PickedManipulatorId{pickedManipulatorId, intersectionDistance}; + return PickedManipulatorId{ pickedManipulatorId, intersectionDistance }; } ManipulatorManager::ConsumeMouseMoveResult ManipulatorManager::ConsumeViewportMouseMove( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.h index 5f57738b8c..66b38579ef 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorManager.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -23,7 +23,7 @@ namespace AzFramework { struct CameraState; class DebugDisplayRequests; -} +} // namespace AzFramework namespace AzToolsFramework { @@ -40,15 +40,15 @@ namespace AzToolsFramework class BaseManipulator; class LinearManipulator; - /// State of overall manipulator manager. + //! State of overall manipulator manager. struct ManipulatorManagerState { bool m_interacting; }; - /// This class serves to manage all relevant mouse events and coordinate all registered manipulators to function properly. - /// ManipulatorManager does not manage the life cycle of specific manipulators. The users of manipulators are responsible - /// for creating and deleting them at right time, as well as registering and unregistering accordingly. + //! This class serves to manage all relevant mouse events and coordinate all registered manipulators to function properly. + //! ManipulatorManager does not manage the life cycle of specific manipulators. The users of manipulators are responsible + //! for creating and deleting them at right time, as well as registering and unregistering accordingly. class ManipulatorManager : private ManipulatorManagerRequestBus::Handler , private EditorEntityInfoNotificationBus::Handler @@ -59,7 +59,7 @@ namespace AzToolsFramework explicit ManipulatorManager(ManipulatorManagerId managerId); ~ManipulatorManager(); - /// The result of consuming a mouse move. + //! The result of consuming a mouse move. enum class ConsumeMouseMoveResult { None, @@ -80,57 +80,52 @@ namespace AzToolsFramework void DeleteManipulatorBound(Picking::RegisteredBoundId boundId) override; void SetBoundDirty(Picking::RegisteredBoundId boundId) override; Picking::RegisteredBoundId UpdateBound( - ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, - const Picking::BoundRequestShapeBase& boundShapeData) override; - bool Interacting() const override { return m_activeManipulator != nullptr; } + ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData) override; + bool Interacting() const override + { + return m_activeManipulator != nullptr; + } void DrawManipulators( AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction); - // O3DE_DEPRECATED(LY-117150) - /// Check if the modifier key state has changed - if so we may need to refresh - /// certain manipulator bounds. - AZ_DEPRECATED( - void CheckModifierKeysChanged( - ViewportInteraction::KeyboardModifiers keyboardModifiers, - const ViewportInteraction::MousePick& mousePick), - "CheckModifierKeysChanged is deprecated and will be removed in a future release"); - protected: - /// @param rayOrigin The origin of the ray to test intersection with. - /// @param rayDirection The direction of the ray to test intersection with. - /// @param[out] rayIntersectionDistance The result intersecting point equals "rayOrigin + rayIntersectionDistance * rayDirection". - /// @return A pointer to a manipulator that the ray intersects. Null pointer if no intersection is detected. + //! @param rayOrigin The origin of the ray to test intersection with. + //! @param rayDirection The direction of the ray to test intersection with. + //! @param[out] rayIntersectionDistance The result intersecting point equals "rayOrigin + rayIntersectionDistance * rayDirection". + //! @return A pointer to a manipulator that the ray intersects. Null pointer if no intersection is detected. AZStd::shared_ptr PerformRaycast( const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance); // EditorEntityInfoNotifications ... void OnEntityInfoUpdatedVisibility(AZ::EntityId entityId, bool visible) override; - /// Alias for a Manipulator and intersection distance. + //! Alias for a Manipulator and intersection distance. using PickedManipulator = AZStd::tuple, float>; - /// Alias for a ManipulatorId and intersection distance. + //! Alias for a ManipulatorId and intersection distance. using PickedManipulatorId = AZStd::tuple; - /// Return the picked manipulator and intersection distance if a manipulator was intersected. + //! Return the picked manipulator and intersection distance if a manipulator was intersected. AZStd::optional PickManipulator(const ViewportInteraction::MousePick& mousePick); - /// Wrapper for PickManipulator to return the ManipulatorId directly. + //! Wrapper for PickManipulator to return the ManipulatorId directly. PickedManipulatorId PickManipulatorId(const ViewportInteraction::MousePick& mousePick); - /// Called once per frame after all manipulators have been drawn (and their - /// bounds updated if required). + //! Called once per frame after all manipulators have been drawn (and their + //! bounds updated if required). void RefreshMouseOverState(const ViewportInteraction::MousePick& mousePick); - ManipulatorManagerId m_manipulatorManagerId; ///< This manipulator manager's id. - ManipulatorId m_nextManipulatorIdToGenerate; ///< Id to use for the next manipulator that is registered with this manager. + ManipulatorManagerId m_manipulatorManagerId; //!< This manipulator manager's id. + ManipulatorId m_nextManipulatorIdToGenerate; //!< Id to use for the next manipulator that is registered with this manager. - AZStd::unordered_map> m_manipulatorIdToPtrMap; ///< Mapping from a manipulatorId to the corresponding manipulator. - AZStd::unordered_map m_boundIdToManipulatorIdMap; ///< Mapping from a boundId to the corresponding manipulatorId. + AZStd::unordered_map> + m_manipulatorIdToPtrMap; //!< Mapping from a manipulatorId to the corresponding manipulator. + AZStd::unordered_map + m_boundIdToManipulatorIdMap; //!< Mapping from a boundId to the corresponding manipulatorId. - AZStd::shared_ptr m_activeManipulator; ///< The manipulator we are currently interacting with. - Picking::ManipulatorBoundManager m_boundManager; ///< All active manipulator bounds that could be interacted with. + AZStd::shared_ptr m_activeManipulator; //!< The manipulator we are currently interacting with. + Picking::ManipulatorBoundManager m_boundManager; //!< All active manipulator bounds that could be interacted with. }; // The main/default ManipulatorManagerId to be used for diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp index 8a6398d025..427bb9e9d1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ManipulatorSnapping.h" @@ -19,19 +19,27 @@ #include AZ_CVAR( - AZ::Color, cl_viewportGridMainColor, AZ::Color::CreateFromRgba(26, 26, 26, 127), nullptr, - AZ::ConsoleFunctorFlags::Null, "Main color for snapping grid"); + AZ::Color, + cl_viewportGridMainColor, + AZ::Color::CreateFromRgba(26, 26, 26, 127), + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Main color for snapping grid"); AZ_CVAR( - AZ::Color, cl_viewportGridFadeColor, AZ::Color::CreateFromRgba(127, 127, 127, 0), nullptr, - AZ::ConsoleFunctorFlags::Null, "Fade color for snapping grid"); + AZ::Color, + cl_viewportGridFadeColor, + AZ::Color::CreateFromRgba(127, 127, 127, 0), + nullptr, + AZ::ConsoleFunctorFlags::Null, + "Fade color for snapping grid"); +AZ_CVAR(int, cl_viewportGridSquareCount, 20, nullptr, AZ::ConsoleFunctorFlags::Null, "Number of grid squares for snapping grid"); +AZ_CVAR(float, cl_viewportGridLineWidth, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Width of grid lines for snapping grid"); AZ_CVAR( - int, cl_viewportGridSquareCount, 20, nullptr, AZ::ConsoleFunctorFlags::Null, - "Number of grid squares for snapping grid"); -AZ_CVAR( - float, cl_viewportGridLineWidth, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, - "Width of grid lines for snapping grid"); -AZ_CVAR( - float, cl_viewportFadeLineDistanceScale, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + cl_viewportFadeLineDistanceScale, + 1.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The scale to be applied to the line that fades out (scales the current gridSize)"); namespace AzToolsFramework @@ -43,16 +51,17 @@ namespace AzToolsFramework } ManipulatorInteraction BuildManipulatorInteraction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection) + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Vector3& worldRayOrigin, + const AZ::Vector3& worldRayDirection) { const AZ::Transform worldFromLocalUniform = AzToolsFramework::TransformUniformScale(worldFromLocal); const AZ::Transform localFromWorldUniform = worldFromLocalUniform.GetInverse(); - return {localFromWorldUniform.TransformPoint(worldRayOrigin), - TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection), - NonUniformScaleReciprocal(nonUniformScale), - ScaleReciprocal(worldFromLocalUniform)}; + return { localFromWorldUniform.TransformPoint(worldRayOrigin), + TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection), NonUniformScaleReciprocal(nonUniformScale), + ScaleReciprocal(worldFromLocalUniform) }; } struct SnapAdjustment @@ -87,8 +96,7 @@ namespace AzToolsFramework } AZ::Vector3 CalculateSnappedTerrainPosition( - const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, - const int viewportId, const float gridSize) + const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, const int viewportId, const float gridSize) { const AZ::Transform localFromWorld = worldFromLocal.GetInverse(); const AZ::Vector3 localSurfacePosition = localFromWorld.TransformPoint(worldSurfacePosition); @@ -101,8 +109,7 @@ namespace AzToolsFramework // find terrain height at xy snapped location float terrainHeight = 0.0f; ViewportInteraction::MainEditorViewportInteractionRequestBus::EventResult( - terrainHeight, viewportId, - &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::TerrainHeight, + terrainHeight, viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::TerrainHeight, Vector3ToVector2(worldFromLocal.TransformPoint(localSnappedSurfacePosition))); // set snapped z value to terrain height @@ -116,8 +123,7 @@ namespace AzToolsFramework { bool snapping = false; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - snapping, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled); + snapping, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled); return snapping; } @@ -126,8 +132,7 @@ namespace AzToolsFramework { float gridSize = 0.0f; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - gridSize, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize); + gridSize, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize); return gridSize; } @@ -136,7 +141,8 @@ namespace AzToolsFramework { bool snapping = GridSnapping(viewportId); const float gridSize = GridSize(viewportId); - if (AZ::IsClose(gridSize, 0.0f, 1e-2f)) // Same threshold value as min value for m_spinBox in SnapToWidget constructor in MainWindow.cpp + if (AZ::IsClose( + gridSize, 0.0f, 1e-2f)) // Same threshold value as min value for m_spinBox in SnapToWidget constructor in MainWindow.cpp { snapping = false; } @@ -148,8 +154,7 @@ namespace AzToolsFramework { bool snapping = false; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - snapping, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled); + snapping, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled); return snapping; } @@ -158,8 +163,7 @@ namespace AzToolsFramework { float angle = 0.0f; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - angle, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleStep); + angle, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleStep); return angle; } @@ -168,14 +172,12 @@ namespace AzToolsFramework { bool show = false; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - show, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::ShowGrid); + show, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::ShowGrid); return show; } - void DrawSnappingGrid( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, const float squareSize) + void DrawSnappingGrid(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, const float squareSize) { debugDisplay.PushMatrix(worldFromLocal); @@ -197,21 +199,17 @@ namespace AzToolsFramework // draw the faded end parts of the grid lines debugDisplay.DrawLine( - AZ::Vector3(lineOffset, -halfGridSize, 0.0f), - AZ::Vector3(lineOffset, -(halfGridSize + fadeLineLength), 0.0f), + AZ::Vector3(lineOffset, -halfGridSize, 0.0f), AZ::Vector3(lineOffset, -(halfGridSize + fadeLineLength), 0.0f), gridMainColor, gridFadeColor); debugDisplay.DrawLine( - AZ::Vector3(lineOffset, halfGridSize, 0.0f), - AZ::Vector3(lineOffset, (halfGridSize + fadeLineLength), 0.0f), + AZ::Vector3(lineOffset, halfGridSize, 0.0f), AZ::Vector3(lineOffset, (halfGridSize + fadeLineLength), 0.0f), gridMainColor, + gridFadeColor); + debugDisplay.DrawLine( + AZ::Vector3(-halfGridSize, lineOffset, 0.0f), AZ::Vector3(-(halfGridSize + fadeLineLength), lineOffset, 0.0f), gridMainColor, gridFadeColor); debugDisplay.DrawLine( - AZ::Vector3(-halfGridSize, lineOffset, 0.0f), - AZ::Vector3(-(halfGridSize + fadeLineLength), lineOffset, 0.0f), - gridMainColor, gridFadeColor); - debugDisplay.DrawLine( - AZ::Vector3(halfGridSize, lineOffset, 0.0f), - AZ::Vector3((halfGridSize + fadeLineLength), lineOffset, 0.0f), - gridMainColor, gridFadeColor); + AZ::Vector3(halfGridSize, lineOffset, 0.0f), AZ::Vector3((halfGridSize + fadeLineLength), lineOffset, 0.0f), gridMainColor, + gridFadeColor); // build a vector of the main grid lines to draw (start and end positions) lines.push_back(AZ::Vector3(lineOffset, -halfGridSize, 0.0f)); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h index 11860780c7..f2fa104d4c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSnapping.h @@ -1,19 +1,19 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once -#include #include +#include namespace AzFramework { @@ -22,7 +22,7 @@ namespace AzFramework namespace AzToolsFramework { - /// Structure to encapsulate grid snapping properties. + //! Structure to encapsulate grid snapping properties. struct GridSnapParameters { GridSnapParameters(bool gridSnap, float gridSize); @@ -31,96 +31,92 @@ namespace AzToolsFramework float m_gridSize; }; - /// Structure to hold transformed incoming viewport interaction from world space to manipulator space. + //! Structure to hold transformed incoming viewport interaction from world space to manipulator space. struct ManipulatorInteraction { - AZ::Vector3 m_localRayOrigin; ///< The ray origin (start) in the reference from of the manipulator. - AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator. - AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied - ///< separately from the transform. - float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the - ///< ray from world space to local space. + AZ::Vector3 m_localRayOrigin; //!< The ray origin (start) in the reference from of the manipulator. + AZ::Vector3 m_localRayDirection; //!< The ray direction in the reference from of the manipulator. + AZ::Vector3 m_nonUniformScaleReciprocal; //!< Handles inverting any non-uniform scale which was applied + //!< separately from the transform. + float m_scaleReciprocal; //!< The scale reciprocal (1.0 / scale) of the transform used to move the + //!< ray from world space to local space. }; - /// Build a ManipulatorInteraction structure from the incoming viewport interaction. + //! Build a ManipulatorInteraction structure from the incoming viewport interaction. ManipulatorInteraction BuildManipulatorInteraction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection); + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Vector3& worldRayOrigin, + const AZ::Vector3& worldRayDirection); - /// Calculate the offset along an axis to adjust a position to stay snapped to a given grid size. - /// @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2, - /// 0.7 snaps to 1.0 -> delta 0.3). - AZ::Vector3 CalculateSnappedOffset( - const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); + //! Calculate the offset along an axis to adjust a position to stay snapped to a given grid size. + //! @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2, + //! 0.7 snaps to 1.0 -> delta 0.3). + AZ::Vector3 CalculateSnappedOffset(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); - /// Return the amount to snap from the starting position given the current grid size. - /// @note A movement of more than half size (in either direction) will cause a snap by size. + //! Return the amount to snap from the starting position given the current grid size. + //! @note A movement of more than half size (in either direction) will cause a snap by size. AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size); - /// For a given point on the terrain, calculate the closest xy position snapped to the grid - /// (z position is aligned to terrain height, not snapped to z grid) + //! For a given point on the terrain, calculate the closest xy position snapped to the grid + //! (z position is aligned to terrain height, not snapped to z grid) AZ::Vector3 CalculateSnappedTerrainPosition( - const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, - int viewportId, float gridSize); + const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, int viewportId, float gridSize); - /// Wrapper for grid snapping and grid size bus calls. + //! Wrapper for grid snapping and grid size bus calls. GridSnapParameters GridSnapSettings(int viewportId); - /// Wrapper for angle snapping enabled bus call. + //! Wrapper for angle snapping enabled bus call. bool AngleSnapping(int viewportId); - /// Wrapper for angle snapping increment bus call. - /// @return Angle in degrees + //! Wrapper for angle snapping increment bus call. + //! @return Angle in degrees. float AngleStep(int viewportId); - /// Wrapper for grid rendering check call. + //! Wrapper for grid rendering check call. bool ShowingGrid(int viewportId); - /// Render the grid used for snapping. - void DrawSnappingGrid( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, float squareSize); + //! Render the grid used for snapping. + void DrawSnappingGrid(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, float squareSize); - /// Round to x number of significant digits. - /// @param value Number to round. - /// @param exponent Precision to use when rounding. + //! Round to x number of significant digits. + //! @param value Number to round. + //! @param exponent Precision to use when rounding. inline float Round(const float value, const float exponent) { const float precision = std::pow(10.0f, exponent); return roundf(value * precision) / precision; } - /// Round to 3 significant digits (3 digits common usage). + //! Round to 3 significant digits (3 digits common usage). inline float Round3(const float value) { return Round(value, 3.0f); } - /// Util to return sign of floating point number. - /// value > 0 return 1.0 - /// value < 0 return -1.0 - /// value == 0 return 0.0 + //! Util to return sign of floating point number. + //! value > 0 return 1.0 + //! value < 0 return -1.0 + //! value == 0 return 0.0 inline float Sign(const float value) { return static_cast((0.0f < value) - (value < 0.0f)); } - /// Find the max scale element and return the reciprocal of it. - /// Note: The reciprocal will be rounded to three significant digits to eliminate - /// noise in the value returned when dealing with values far from the origin. + //! Find the max scale element and return the reciprocal of it. + //! Note: The reciprocal will be rounded to three significant digits to eliminate + //! noise in the value returned when dealing with values far from the origin. inline float ScaleReciprocal(const AZ::Transform& transform) { return Round3(1.0f / transform.GetUniformScale()); } - /// Find the reciprocal of the non-uniform scale. - /// Each element will be rounded to three significant digits to eliminate noise - /// when dealing with values far from the origin. + //! Find the reciprocal of the non-uniform scale. + //! Each element will be rounded to three significant digits to eliminate noise + //! when dealing with values far from the origin. inline AZ::Vector3 NonUniformScaleReciprocal(const AZ::Vector3& nonUniformScale) { AZ::Vector3 scaleReciprocal = nonUniformScale.GetReciprocal(); - return AZ::Vector3( - Round3(scaleReciprocal.GetX()), - Round3(scaleReciprocal.GetY()), - Round3(scaleReciprocal.GetZ())); + return AZ::Vector3(Round3(scaleReciprocal.GetX()), Round3(scaleReciprocal.GetY()), Round3(scaleReciprocal.GetZ())); } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h index e26c6b8947..7c1176dd2c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorSpace.h @@ -20,7 +20,7 @@ namespace AZ namespace AzToolsFramework { - /// Handles location for manipulators which have a global space but no local transformation. + //! Handles location for manipulators which have a global space but no local transformation. class ManipulatorSpace { public: @@ -32,17 +32,16 @@ namespace AzToolsFramework const AZ::Vector3& GetNonUniformScale() const; void SetNonUniformScale(const AZ::Vector3& nonUniformScale); - /// Calculates a transform combining the space and local transform, taking non-uniform scale into account. + //! Calculates a transform combining the space and local transform, taking non-uniform scale into account. AZ::Transform ApplySpace(const AZ::Transform& localTransform) const; private: - AZ::Transform m_space = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in. - AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); ///< Handles non-uniform scale for the space the manipulator is in. + AZ::Transform m_space = AZ::Transform::CreateIdentity(); //!< Space the manipulator is in. + AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); //!< Handles non-uniform scale for the space the manipulator is in. }; - /// Handles location for manipulators which have a global space and a local position, but no local rotation. - class ManipulatorSpaceWithLocalPosition - : public ManipulatorSpace + //! Handles location for manipulators which have a global space and a local position, but no local rotation. + class ManipulatorSpaceWithLocalPosition : public ManipulatorSpace { public: AZ_TYPE_INFO(ManipulatorSpaceWithLocalPosition, "{47BE15AF-60A8-436B-8F3F-7DDFB97220E6}") @@ -52,12 +51,11 @@ namespace AzToolsFramework void SetLocalPosition(const AZ::Vector3& localPosition); private: - AZ::Vector3 m_localPosition = AZ::Vector3::CreateZero(); ///< Position in local space. + AZ::Vector3 m_localPosition = AZ::Vector3::CreateZero(); //!< Position in local space. }; - /// Handles location for manipulators which have a global space and a local transform (position and rotation). - class ManipulatorSpaceWithLocalTransform - : public ManipulatorSpace + //! Handles location for manipulators which have a global space and a local transform (position and rotation). + class ManipulatorSpaceWithLocalTransform : public ManipulatorSpace { public: AZ_TYPE_INFO(ManipulatorSpaceWithLocalTransform, "{6D100797-1DD8-45B0-A21C-8893B770C0BC}") @@ -72,6 +70,6 @@ namespace AzToolsFramework void SetLocalOrientation(const AZ::Quaternion& localOrientation); private: - AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform. + AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); //!< Local transform. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp index 150e23041d..a4c4a59ee6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.cpp @@ -1,26 +1,26 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ManipulatorView.h" -#include #include +#include #include #include #include -#include #include -#include #include +#include +#include #include #include #include @@ -33,8 +33,7 @@ namespace AzToolsFramework AZ::Transform WorldFromLocalWithUniformScale(const AZ::EntityId entityId) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); return TransformUniformScale(worldFromLocal); } @@ -56,13 +55,16 @@ namespace AzToolsFramework return AzToolsFramework::TransformDirectionNoScaling(m_worldFromLocal, direction); } - /// Take into account the location of the camera and orientate the axis so it faces the camera. - /// if we did correct the camera (shouldCorrect is true) then we know the axis facing us it negative. - /// we can use this to change the rendering for a flipped axis if we wish. + // Take into account the location of the camera and orientate the axis so it faces the camera. + // if we did correct the camera (shouldCorrect is true) then we know the axis facing us it negative. + // we can use this to change the rendering for a flipped axis if we wish. static void CameraCorrectAxis( - const AZ::Vector3& axis, AZ::Vector3& correctedAxis, const ManipulatorManagerState& managerState, + const AZ::Vector3& axis, + AZ::Vector3& correctedAxis, + const ManipulatorManagerState& managerState, const ViewportInteraction::MouseInteraction& mouseInteraction, - const AZ::Transform& worldFromLocal, const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& localPosition, const AzFramework::CameraState& cameraState, bool* shouldCorrect = nullptr) { @@ -74,9 +76,7 @@ namespace AzToolsFramework const bool correcting = ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState); // the corrected axis, if no flip was required, output == input - correctedAxis = correcting - ? -axis - : axis; + correctedAxis = correcting ? -axis : axis; // optional out ref to use if we care about the result if (shouldCorrect) @@ -86,10 +86,13 @@ namespace AzToolsFramework } } - /// Calculate quad bound in world space. + // calculate quad bound in world space. static Picking::BoundShapeQuad CalculateQuadBound( - const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState, - const AZ::Vector3& axis1, const AZ::Vector3& axis2, const float size) + const AZ::Vector3& localPosition, + const ManipulatorState& manipulatorState, + const AZ::Vector3& axis1, + const AZ::Vector3& axis2, + const float size) { const AZ::Vector3 worldPosition = manipulatorState.TransformPoint(localPosition); const AZ::Vector3 endAxis1World = manipulatorState.TransformDirectionNoScaling(axis1) * size; @@ -104,8 +107,10 @@ namespace AzToolsFramework } static Picking::BoundShapeQuad CalculateQuadBoundBillboard( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const float size, const AzFramework::CameraState& cameraState) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const float size, + const AzFramework::CameraState& cameraState) { const AZ::Vector3 worldPosition = worldFromLocal.TransformPoint(localPosition); @@ -117,10 +122,13 @@ namespace AzToolsFramework return quadBound; } - /// Calculate line bound in world space (axis and length). + // calculate line bound in world space (axis and length). static Picking::BoundShapeLineSegment CalculateLineBound( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const AZ::Vector3& axis, const float length, const float width) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& axis, + const float length, + const float width) { Picking::BoundShapeLineSegment lineBound; lineBound.m_start = worldFromLocal.TransformPoint(localPosition); @@ -129,7 +137,7 @@ namespace AzToolsFramework return lineBound; } - /// Calculate line bound in world space (start and end point). + // calculate line bound in world space (start and end point). static Picking::BoundShapeLineSegment CalculateLineBound( const AZ::Vector3& localStartPosition, const AZ::Vector3& localEndPosition, @@ -143,10 +151,14 @@ namespace AzToolsFramework return lineBound; } - /// Calculate cone bound in world space. + // calculate cone bound in world space. static Picking::BoundShapeCone CalculateConeBound( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const AZ::Vector3& axis, const AZ::Vector3& offset, const float length, const float radius) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& axis, + const AZ::Vector3& offset, + const float length, + const float radius) { Picking::BoundShapeCone coneBound; coneBound.m_radius = radius; @@ -156,10 +168,13 @@ namespace AzToolsFramework return coneBound; } - /// Calculate box bound in world space. + // calculate box bound in world space. static Picking::BoundShapeBox CalculateBoxBound( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const AZ::Quaternion& orientation, const AZ::Vector3& offset, const AZ::Vector3& halfExtents) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Quaternion& orientation, + const AZ::Vector3& offset, + const AZ::Vector3& halfExtents) { Picking::BoundShapeBox boxBound; boxBound.m_halfExtents = halfExtents; @@ -168,10 +183,13 @@ namespace AzToolsFramework return boxBound; } - /// Calculate cylinder bound in world space. + // calculate cylinder bound in world space. static Picking::BoundShapeCylinder CalculateCylinderBound( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const AZ::Vector3& axis, const float length, const float radius) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& axis, + const float length, + const float radius) { Picking::BoundShapeCylinder boxBound; boxBound.m_base = worldFromLocal.TransformPoint(localPosition); @@ -181,10 +199,9 @@ namespace AzToolsFramework return boxBound; } - /// Calculate sphere bound in world space. + // calculate sphere bound in world space. static Picking::BoundShapeSphere CalculateSphereBound( - const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState, - const float radius) + const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState, const float radius) { Picking::BoundShapeSphere sphereBound; sphereBound.m_center = manipulatorState.TransformPoint(localPosition); @@ -192,10 +209,13 @@ namespace AzToolsFramework return sphereBound; } - /// Calculate torus bound in world space. + // calculate torus bound in world space. static Picking::BoundShapeTorus CalculateTorusBound( - const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal, - const AZ::Vector3& axis, const float radius, const float width) + const AZ::Vector3& localPosition, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& axis, + const float radius, + const float width) { Picking::BoundShapeTorus torusBound; torusBound.m_center = worldFromLocal.TransformPoint(localPosition); @@ -205,7 +225,7 @@ namespace AzToolsFramework return torusBound; } - /// Calculate spline bound in world space. + // calculate spline bound in world space. static Picking::BoundShapeSpline CalculateSplineBound( const AZStd::weak_ptr& spline, const AZ::Transform& worldFromLocal, const float width) { @@ -224,8 +244,7 @@ namespace AzToolsFramework return lineWidth[mouseOver]; } - static AZ::Color ViewColor( - const bool mouseOver, const AZ::Color& defaultColor, const AZ::Color& mouseOverColor) + static AZ::Color ViewColor(const bool mouseOver, const AZ::Color& defaultColor, const AZ::Color& mouseOverColor) { const AZStd::array viewColor = { { defaultColor, mouseOverColor } }; return viewColor[mouseOver].GetAsVector4(); @@ -250,19 +269,16 @@ namespace AzToolsFramework void ManipulatorView::SetBoundDirty(const ManipulatorManagerId managerId) { - ManipulatorManagerRequestBus::Event( - managerId, &ManipulatorManagerRequestBus::Events::SetBoundDirty, m_boundId); + ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::SetBoundDirty, m_boundId); m_boundDirty = true; } void ManipulatorView::RefreshBound( - const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, - const Picking::BoundRequestShapeBase& bound) + const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound) { ManipulatorManagerRequestBus::EventResult( - m_boundId, managerId, &ManipulatorManagerRequestBus::Events::UpdateBound, - manipulatorId, m_boundId, bound); + m_boundId, managerId, &ManipulatorManagerRequestBus::Events::UpdateBound, manipulatorId, m_boundId, bound); // store the manager id if we know the bound has been registered m_managerId = managerId; @@ -271,8 +287,7 @@ namespace AzToolsFramework } void ManipulatorView::RefreshBoundInternal( - const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, - const Picking::BoundRequestShapeBase& bound) + const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound) { // update the manipulator's bounds if necessary // if m_screenSizeFixed is true, any camera movement can potentially change the size @@ -287,8 +302,7 @@ namespace AzToolsFramework { if (m_boundId != Picking::InvalidBoundId) { - ManipulatorManagerRequestBus::Event( - managerId, &ManipulatorManagerRequestBus::Events::DeleteManipulatorBound, m_boundId); + ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::DeleteManipulatorBound, m_boundId); m_boundId = Picking::InvalidBoundId; } @@ -297,33 +311,34 @@ namespace AzToolsFramework float ManipulatorView::ManipulatorViewScaleMultiplier( const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const { - return ScreenSizeFixed() - ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) - : 1.0f; + return ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ManipulatorViewQuad::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { const AZ::Vector3 axis1 = m_axis1; const AZ::Vector3 axis2 = m_axis2; CameraCorrectAxis( - axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState); + axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); CameraCorrectAxis( - axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState); + axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); - const Picking::BoundShapeQuad quadBound = - CalculateQuadBound( - manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2, - m_size * ManipulatorViewScaleMultiplier( + const Picking::BoundShapeQuad quadBound = CalculateQuadBound( + manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2, + m_size * + ManipulatorViewScaleMultiplier( manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState)); debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver)); @@ -339,9 +354,7 @@ namespace AzToolsFramework debugDisplay.SetColor(Vector3ToVector4(m_mouseOverColor.GetAsVector3(), 0.5f)); debugDisplay.CullOff(); - debugDisplay.DrawQuad( - quadBound.m_corner1, quadBound.m_corner2, - quadBound.m_corner3, quadBound.m_corner4); + debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4); debugDisplay.CullOn(); } @@ -349,41 +362,46 @@ namespace AzToolsFramework } void ManipulatorViewQuadBillboard::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& /*managerState*/, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& /*mouseInteraction*/) { - const Picking::BoundShapeQuad quadBound = - CalculateQuadBoundBillboard(manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, - m_size * ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState), cameraState); + const Picking::BoundShapeQuad quadBound = CalculateQuadBoundBillboard( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, + m_size * + ManipulatorViewScaleMultiplier( + manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState), + cameraState); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); - debugDisplay.DrawQuad( - quadBound.m_corner1, quadBound.m_corner2, - quadBound.m_corner3, quadBound.m_corner4); + debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4); RefreshBoundInternal(managerId, manipulatorId, quadBound); } void ManipulatorViewLine::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); CameraCorrectAxis( - m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState); + m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); - const Picking::BoundShapeLineSegment lineBound = - CalculateLineBound( - manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, - m_cameraCorrectedAxis, m_length * viewScale, m_width * viewScale); + const Picking::BoundShapeLineSegment lineBound = CalculateLineBound( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_length * viewScale, + m_width * viewScale); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver)); @@ -393,13 +411,16 @@ namespace AzToolsFramework } void ManipulatorViewLineSelect::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& /*managerState*/, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); const Picking::BoundShapeLineSegment lineBound = CalculateLineBound(m_localStart, m_localEnd, manipulatorState, m_width * viewScale); @@ -407,44 +428,42 @@ namespace AzToolsFramework if (manipulatorState.m_mouseOver) { const LineSegmentSelectionManipulator::Action action = CalculateManipulationDataAction( - manipulatorState.m_worldFromLocal, manipulatorState.m_nonUniformScale, - mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection, - cameraState.m_farClip, m_localStart, m_localEnd); + manipulatorState.m_worldFromLocal, manipulatorState.m_nonUniformScale, mouseInteraction.m_mousePick.m_rayOrigin, + mouseInteraction.m_mousePick.m_rayDirection, cameraState.m_farClip, m_localStart, m_localEnd); const AZ::Vector3 worldLineHitPosition = manipulatorState.TransformPoint(action.m_localLineHitPosition); debugDisplay.SetColor(AZ::Vector4(0.0f, 1.0f, 0.0f, 1.0f)); debugDisplay.DrawBall( - worldLineHitPosition, ManipulatorViewScaleMultiplier(worldLineHitPosition, cameraState) - * g_defaultManipulatorSphereRadius, false); + worldLineHitPosition, ManipulatorViewScaleMultiplier(worldLineHitPosition, cameraState) * g_defaultManipulatorSphereRadius, + false); } RefreshBoundInternal(managerId, manipulatorId, lineBound); } void ManipulatorViewCone::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); CameraCorrectAxis( - m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, - cameraState, &m_shouldCorrect); + m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState, &m_shouldCorrect); CameraCorrectAxis( - m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState); + m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); - const Picking::BoundShapeCone coneBound = - CalculateConeBound( - manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, - m_cameraCorrectedOffset * viewScale, - m_length * viewScale, - m_radius * viewScale); + const Picking::BoundShapeCone coneBound = CalculateConeBound( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_cameraCorrectedOffset * viewScale, + m_length * viewScale, m_radius * viewScale); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); if (m_shouldCorrect) @@ -460,73 +479,77 @@ namespace AzToolsFramework } void ManipulatorViewBox::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); const AZ::Quaternion orientation = m_orientation; CameraCorrectAxis( - m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, - cameraState); + m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); - const Picking::BoundShapeBox boxBound = - CalculateBoxBound(manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, orientation, - m_cameraCorrectedOffset * viewScale, - m_halfExtents * viewScale); + const Picking::BoundShapeBox boxBound = CalculateBoxBound( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, orientation, m_cameraCorrectedOffset * viewScale, + m_halfExtents * viewScale); const AZ::Vector3 xAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisX()); const AZ::Vector3 yAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisY()); const AZ::Vector3 zAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisZ()); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); - debugDisplay.DrawSolidOBB(boxBound.m_center, - xAxis, yAxis, zAxis, boxBound.m_halfExtents); + debugDisplay.DrawSolidOBB(boxBound.m_center, xAxis, yAxis, zAxis, boxBound.m_halfExtents); RefreshBoundInternal(managerId, manipulatorId, boxBound); } void ManipulatorViewCylinder::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); CameraCorrectAxis( - m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, - manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState); + m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal, + manipulatorState.m_localPosition, cameraState); - const Picking::BoundShapeCylinder cylinderBound = - CalculateCylinderBound( - manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, - m_length * viewScale, - m_radius * viewScale); + const Picking::BoundShapeCylinder cylinderBound = CalculateCylinderBound( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_length * viewScale, + m_radius * viewScale); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); - debugDisplay.DrawSolidCylinder(cylinderBound.m_base + cylinderBound.m_axis * cylinderBound.m_height * 0.5f, - cylinderBound.m_axis, cylinderBound.m_radius, cylinderBound.m_height, false); + debugDisplay.DrawSolidCylinder( + cylinderBound.m_base + cylinderBound.m_axis * cylinderBound.m_height * 0.5f, cylinderBound.m_axis, cylinderBound.m_radius, + cylinderBound.m_height, false); RefreshBoundInternal(managerId, manipulatorId, cylinderBound); } void ManipulatorViewSphere::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& /*managerState*/, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const Picking::BoundShapeSphere sphereBound = - CalculateSphereBound(manipulatorState.m_localPosition, manipulatorState, - m_radius * ManipulatorViewScaleMultiplier( - manipulatorState.TransformPoint(manipulatorState.m_localPosition), cameraState)); + const Picking::BoundShapeSphere sphereBound = CalculateSphereBound( + manipulatorState.m_localPosition, manipulatorState, + m_radius * ManipulatorViewScaleMultiplier(manipulatorState.TransformPoint(manipulatorState.m_localPosition), cameraState)); if (m_depthTest) { @@ -545,31 +568,32 @@ namespace AzToolsFramework } void ManipulatorViewCircle::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& /*managerState*/, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& /*mouseInteraction*/) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); - const Picking::BoundShapeTorus torusBound = - CalculateTorusBound( - manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_axis, - m_radius * viewScale, - m_width * viewScale); + const Picking::BoundShapeTorus torusBound = CalculateTorusBound( + manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_axis, m_radius * viewScale, m_width * viewScale); // transform circle based on delta between default z up axis and other axes const AZ::Transform worldFromLocalWithOrientation = AZ::Transform::CreateTranslation(manipulatorState.m_worldFromLocal.GetTranslation()) * - AZ::Transform::CreateFromQuaternion( - (QuaternionFromTransformNoScaling(manipulatorState.m_worldFromLocal) * - AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), m_axis)).GetNormalized()); + AZ::Transform::CreateFromQuaternion((QuaternionFromTransformNoScaling(manipulatorState.m_worldFromLocal) * + AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), m_axis)) + .GetNormalized()); debugDisplay.CullOn(); debugDisplay.PushMatrix(worldFromLocalWithOrientation); debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4()); - m_drawCircleFunc(debugDisplay, manipulatorState.m_localPosition, torusBound.m_majorRadius, + m_drawCircleFunc( + debugDisplay, manipulatorState.m_localPosition, torusBound.m_majorRadius, worldFromLocalWithOrientation.GetInverse().TransformPoint(cameraState.m_position)); debugDisplay.PopMatrix(); debugDisplay.CullOff(); @@ -578,27 +602,28 @@ namespace AzToolsFramework } void DrawHalfDottedCircle( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, - const float radius, const AZ::Vector3& viewPos) + AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const float radius, const AZ::Vector3& viewPos) { debugDisplay.DrawHalfDottedCircle(position, radius, viewPos); } void DrawFullCircle( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, - const float radius, const AZ::Vector3& /*viewPos*/) + AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const float radius, const AZ::Vector3& /*viewPos*/) { - debugDisplay.DrawCircle(position, radius); + debugDisplay.DrawCircle(position, radius); } void ManipulatorViewSplineSelect::Draw( - const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/, - const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + const ManipulatorManagerId managerId, + const ManipulatorManagerState& /*managerState*/, + const ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) { - const float viewScale = ManipulatorViewScaleMultiplier( - manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); + const float viewScale = + ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState); const Picking::BoundShapeSpline splineBound = CalculateSplineBound(m_spline, manipulatorState.m_worldFromLocal, m_width * viewScale); @@ -606,16 +631,15 @@ namespace AzToolsFramework if (manipulatorState.m_mouseOver) { const SplineSelectionManipulator::Action action = CalculateManipulationDataAction( - manipulatorState.m_worldFromLocal, mouseInteraction.m_mousePick.m_rayOrigin, - mouseInteraction.m_mousePick.m_rayDirection, m_spline); + manipulatorState.m_worldFromLocal, mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection, + m_spline); - const AZ::Vector3 worldSplineHitPosition = - manipulatorState.m_worldFromLocal.TransformPoint(action.m_localSplineHitPosition); + const AZ::Vector3 worldSplineHitPosition = manipulatorState.m_worldFromLocal.TransformPoint(action.m_localSplineHitPosition); debugDisplay.SetColor(m_color.GetAsVector4()); debugDisplay.DrawBall( - worldSplineHitPosition, ManipulatorViewScaleMultiplier(worldSplineHitPosition, cameraState) - * g_defaultManipulatorSphereRadius, false); + worldSplineHitPosition, + ManipulatorViewScaleMultiplier(worldSplineHitPosition, cameraState) * g_defaultManipulatorSphereRadius, false); } RefreshBoundInternal(managerId, manipulatorId, splineBound); @@ -624,8 +648,7 @@ namespace AzToolsFramework /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AZStd::unique_ptr CreateManipulatorViewQuad( - const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, - const AZ::Color& axis2Color, const float size) + const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const float size) { AZStd::unique_ptr viewQuad = AZStd::make_unique(); viewQuad->m_axis1 = planarManipulator.GetAxis1(); @@ -636,8 +659,7 @@ namespace AzToolsFramework return viewQuad; } - AZStd::unique_ptr CreateManipulatorViewQuadBillboard( - const AZ::Color& color, const float size) + AZStd::unique_ptr CreateManipulatorViewQuadBillboard(const AZ::Color& color, const float size) { AZStd::unique_ptr viewQuad = AZStd::make_unique(); viewQuad->m_size = size; @@ -646,8 +668,7 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewLine( - const LinearManipulator& linearManipulator, const AZ::Color& color, - const float length, const float width) + const LinearManipulator& linearManipulator, const AZ::Color& color, const float length, const float width) { AZStd::unique_ptr viewLine = AZStd::make_unique(); viewLine->m_axis = linearManipulator.GetAxis(); @@ -658,8 +679,7 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewLineSelect( - const LineSegmentSelectionManipulator& lineSegmentManipulator, - const AZ::Color& color, const float width) + const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color, const float width) { AZStd::unique_ptr viewLineSelect = AZStd::make_unique(); viewLineSelect->m_localStart = lineSegmentManipulator.GetStart(); @@ -670,8 +690,11 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewCone( - const LinearManipulator& linearManipulator, const AZ::Color& color, - const AZ::Vector3& offset, const float length, const float radius) + const LinearManipulator& linearManipulator, + const AZ::Color& color, + const AZ::Vector3& offset, + const float length, + const float radius) { AZStd::unique_ptr viewCone = AZStd::make_unique(); viewCone->m_axis = linearManipulator.GetAxis(); @@ -683,8 +706,7 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewBox( - const AZ::Transform& transform, const AZ::Color& color, - const AZ::Vector3& offset, const AZ::Vector3& halfExtents) + const AZ::Transform& transform, const AZ::Color& color, const AZ::Vector3& offset, const AZ::Vector3& halfExtents) { AZStd::unique_ptr viewBox = AZStd::make_unique(); viewBox->m_orientation = transform.GetRotation(); @@ -695,8 +717,7 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewCylinder( - const LinearManipulator& linearManipulator, const AZ::Color& color, - const float length, const float radius) + const LinearManipulator& linearManipulator, const AZ::Color& color, const float length, const float radius) { AZStd::unique_ptr viewCylinder = AZStd::make_unique(); viewCylinder->m_axis = linearManipulator.GetAxis(); @@ -718,8 +739,11 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewCircle( - const AngularManipulator& angularManipulator, const AZ::Color& color, - const float radius, const float width, const ManipulatorViewCircle::DrawCircleFunc drawFunc) + const AngularManipulator& angularManipulator, + const AZ::Color& color, + const float radius, + const float width, + const ManipulatorViewCircle::DrawCircleFunc drawFunc) { AZStd::unique_ptr viewCircle = AZStd::make_unique(); viewCircle->m_axis = angularManipulator.GetAxis(); @@ -731,8 +755,7 @@ namespace AzToolsFramework } AZStd::unique_ptr CreateManipulatorViewSplineSelect( - const SplineSelectionManipulator& splineManipulator, - const AZ::Color& color, const float width) + const SplineSelectionManipulator& splineManipulator, const AZ::Color& color, const float width) { AZStd::unique_ptr viewSplineSelect = AZStd::make_unique(); viewSplineSelect->m_spline = splineManipulator.GetSpline(); @@ -741,16 +764,12 @@ namespace AzToolsFramework return viewSplineSelect; } - AZ::Vector3 CalculateViewDirection( - const Manipulators& manipulators, const AZ::Vector3& worldViewPosition) + AZ::Vector3 CalculateViewDirection(const Manipulators& manipulators, const AZ::Vector3& worldViewPosition) { - const AZ::Transform worldFromLocalWithTransform = - manipulators.GetSpace() * manipulators.GetLocalTransform(); + const AZ::Transform worldFromLocalWithTransform = manipulators.GetSpace() * manipulators.GetLocalTransform(); - AZ::Vector3 lookDirection = - (worldFromLocalWithTransform.GetTranslation() - worldViewPosition).GetNormalized(); + AZ::Vector3 lookDirection = (worldFromLocalWithTransform.GetTranslation() - worldViewPosition).GetNormalized(); - return TransformDirectionNoScaling( - worldFromLocalWithTransform.GetInverse(), lookDirection); + return TransformDirectionNoScaling(worldFromLocalWithTransform.GetInverse(), lookDirection); } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h index da426d2340..8573f8ce32 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ManipulatorView.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -26,13 +26,12 @@ namespace AzToolsFramework class LineSegmentSelectionManipulator; class SplineSelectionManipulator; - using DecideColorFn = AZStd::function; + using DecideColorFn = + AZStd::function; extern const float g_defaultManipulatorSphereRadius; - /// State of an individual manipulator. + //! State of an individual manipulator. struct ManipulatorState { AZ::Transform m_worldFromLocal; @@ -40,18 +39,18 @@ namespace AzToolsFramework AZ::Vector3 m_localPosition; bool m_mouseOver; - /// Transforms a point, taking non-uniform scale into account. + //! Transforms a point, taking non-uniform scale into account. AZ::Vector3 TransformPoint(const AZ::Vector3& point) const; - /// Rotates a direction into the space of the manipulator and normalizes it. - /// Non-uniform scaling and translation are not applied. + //! Rotates a direction into the space of the manipulator and normalizes it. + //! Non-uniform scaling and translation are not applied. AZ::Vector3 TransformDirectionNoScaling(const AZ::Vector3& direction) const; }; - /// The base interface for the visual representation of manipulators. - /// The View represents the appearance and bounds of the manipulator for - /// the user to interact with. Any manipulator can have any view (some may - /// be more appropriate than others in certain cases). + //! The base interface for the visual representation of manipulators. + //! The View represents the appearance and bounds of the manipulator for + //! the user to interact with. Any manipulator can have any view (some may + //! be more appropriate than others in certain cases). class ManipulatorView { public: @@ -65,98 +64,107 @@ namespace AzToolsFramework ManipulatorView& operator=(ManipulatorView&&) = default; void SetBoundDirty(ManipulatorManagerId managerId); - void RefreshBound( - ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound); + void RefreshBound(ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound); void Invalidate(ManipulatorManagerId managerId); virtual void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) = 0; - bool ScreenSizeFixed() const { return m_screenSizeFixed; } + bool ScreenSizeFixed() const + { + return m_screenSizeFixed; + } protected: - AZ::Color m_mouseOverColor = BaseManipulator::s_defaultMouseOverColor; ///< What color should the manipulator - ///< be when the mouse is hovering over it. - /// Scale the manipulator based on the distance - /// from the camera if m_screenSizeFixed is true. - float ManipulatorViewScaleMultiplier( - const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const; + AZ::Color m_mouseOverColor = BaseManipulator::s_defaultMouseOverColor; //!< What color should the manipulator + //!< be when the mouse is hovering over it. + //! Scale the manipulator based on the distance + //! from the camera if m_screenSizeFixed is true. + float ManipulatorViewScaleMultiplier(const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const; - /// Wrap the logic for updating a bound. - /// Should be called at the end of the Draw function once a concrete BoundRequestShape has - /// been created to use for dimensions for rendering. - void RefreshBoundInternal( - ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound); + //! Wrap the logic for updating a bound. + //! Should be called at the end of the Draw function once a concrete BoundRequestShape has + //! been created to use for dimensions for rendering. + void RefreshBoundInternal(ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound); private: - Picking::RegisteredBoundId m_boundId = Picking::InvalidBoundId; ///< Used for hit detection. - ManipulatorManagerId m_managerId = InvalidManipulatorManagerId; /// The manipulator manager this view has been registered with. - bool m_screenSizeFixed = true; ///< Should manipulator size be adjusted based on camera distance. - bool m_boundDirty = true; ///< Do the bounds need to be recalculated. + Picking::RegisteredBoundId m_boundId = Picking::InvalidBoundId; //!< Used for hit detection. + ManipulatorManagerId m_managerId = InvalidManipulatorManagerId; //! The manipulator manager this view has been registered with. + bool m_screenSizeFixed = true; //!< Should manipulator size be adjusted based on camera distance. + bool m_boundDirty = true; //!< Do the bounds need to be recalculated. }; // A collection of views (a manipulator may have 1 - * views) using ManipulatorViews = AZStd::vector>; - /// Display a quad representing part of a plane, rendered as 4 lines. - class ManipulatorViewQuad - : public ManipulatorView + //! Display a quad representing part of a plane, rendered as 4 lines. + class ManipulatorViewQuad : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewQuad, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewQuad, "{D85E1B45-495E-4755-BCF2-6AE45F8BB2B0}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_axis1 = AZ::Vector3(1.0f, 0.0f, 0.0f); AZ::Vector3 m_axis2 = AZ::Vector3(0.0f, 1.0f, 0.0f); AZ::Color m_axis1Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); AZ::Color m_axis2Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); - float m_size = 0.06f; ///< size to render and do mouse ray intersection tests against. + float m_size = 0.06f; //!< size to render and do mouse ray intersection tests against. private: AZ::Vector3 m_cameraCorrectedAxis1; AZ::Vector3 m_cameraCorrectedAxis2; }; - /// A screen aligned quad, centered at the position of the manipulator, display filled. - class ManipulatorViewQuadBillboard - : public ManipulatorView + //! A screen aligned quad, centered at the position of the manipulator, display filled. + class ManipulatorViewQuadBillboard : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewQuadBillboard, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewQuadBillboard, "{C205E967-E8C6-4A73-A31B-41EE5529B15B}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Color m_color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f); - float m_size = 0.005f; ///< size to render and do mouse ray intersection tests against. + float m_size = 0.005f; //!< size to render and do mouse ray intersection tests against. }; - /// Displays a debug style line starting from the manipulator's transform, - /// width determines the click area. - class ManipulatorViewLine - : public ManipulatorView + //! Displays a debug style line starting from the manipulator's transform, + //! width determines the click area. + class ManipulatorViewLine : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewLine, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewLine, "{831EEF66-4A5C-450C-B152-EA4A0BC8A272}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_axis; @@ -168,19 +176,21 @@ namespace AzToolsFramework AZ::Vector3 m_cameraCorrectedAxis; }; - /// Variant of ManipulatorViewLine which instead of using an axis, provides begin and end - /// points for the line. Used for selection when inserting points along a line. - class ManipulatorViewLineSelect - : public ManipulatorView + //! Variant of ManipulatorViewLine which instead of using an axis, provides begin and end + //! points for the line. Used for selection when inserting points along a line. + class ManipulatorViewLineSelect : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewLineSelect, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewLineSelect, "{BF26A947-91F8-4595-9A5B-481876EB2C48}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_localStart; @@ -189,20 +199,22 @@ namespace AzToolsFramework float m_width = 0.0f; }; - /// Displays a filled cone along the specified axis, offset is local translation from - /// the manipulator transform (often used in conjunction with other views to build - /// aggregate views such as arrows - e.g. a line and cone). - class ManipulatorViewCone - : public ManipulatorView + //! Displays a filled cone along the specified axis, offset is local translation from + //! the manipulator transform (often used in conjunction with other views to build + //! aggregate views such as arrows - e.g. a line and cone). + class ManipulatorViewCone : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewCone, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewCone, "{BF042887-1F51-4FD8-8CA5-4A649B4AF356}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_offset; @@ -217,20 +229,22 @@ namespace AzToolsFramework bool m_shouldCorrect = false; }; - /// Displays a filled box, offset is local translation from the manipulator - /// transform, box is often used in conjunction with other views, orientation allows - /// the box to be orientated separately from the manipulator transform. - class ManipulatorViewBox - : public ManipulatorView + //! Displays a filled box, offset is local translation from the manipulator + //! transform, box is often used in conjunction with other views, orientation allows + //! the box to be orientated separately from the manipulator transform. + class ManipulatorViewBox : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewBox, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewBox, "{2D082201-7878-4C1B-A3DD-7A629E5AD598}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_offset; @@ -242,18 +256,20 @@ namespace AzToolsFramework AZ::Vector3 m_cameraCorrectedOffset; }; - /// Displays a filled cylinder along the axis provided. - class ManipulatorViewCylinder - : public ManipulatorView + //! Displays a filled cylinder along the axis provided. + class ManipulatorViewCylinder : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewCylinder, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewCylinder, "{9B8E5EF4-0F85-4CD0-A5FF-3C7097DF58AC}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_axis; @@ -265,20 +281,22 @@ namespace AzToolsFramework AZ::Vector3 m_cameraCorrectedAxis; }; - /// Displays a filled sphere at the transform of the manipulator, often used as - /// a selection manipulator. DecideColorFn allows more complex logic to be used - /// to decide the color of the manipulator (based on hover state etc.) - class ManipulatorViewSphere - : public ManipulatorView + //! Displays a filled sphere at the transform of the manipulator, often used as + //! a selection manipulator. DecideColorFn allows more complex logic to be used + //! to decide the color of the manipulator (based on hover state etc.) + class ManipulatorViewSphere : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewSphere, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewSphere, "{324D8329-6E7B-4A5D-AC8A-8C0E1C984E38}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; float m_radius = 0.0f; @@ -287,23 +305,24 @@ namespace AzToolsFramework bool m_depthTest = false; }; - /// Displays a wire circle. DrawCircleFunc can be used to either draw a full - /// circle or a half dotted circle where the part of the circle facing away - /// from the camera is dotted (useful for angular/rotation manipulators). - class ManipulatorViewCircle - : public ManipulatorView + //! Displays a wire circle. DrawCircleFunc can be used to either draw a full + //! circle or a half dotted circle where the part of the circle facing away + //! from the camera is dotted (useful for angular/rotation manipulators). + class ManipulatorViewCircle : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewCircle, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewCircle, "{26563A03-3E48-49EB-9DCF-30EE4F567FCD}", ManipulatorView) - using DrawCircleFunc = - void(*)(AzFramework::DebugDisplayRequests&, const AZ::Vector3&, float, const AZ::Vector3&); + using DrawCircleFunc = void (*)(AzFramework::DebugDisplayRequests&, const AZ::Vector3&, float, const AZ::Vector3&); void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZ::Vector3 m_axis; @@ -316,26 +335,26 @@ namespace AzToolsFramework // helpers to provide consistent function pointer interface for deciding // on type of circle to draw (see DrawCircleFunc in ManipulatorViewCircle above) void DrawHalfDottedCircle( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, - float radius, const AZ::Vector3& viewPos); + AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, float radius, const AZ::Vector3& viewPos); void DrawFullCircle( - AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, - float radius, const AZ::Vector3& viewPos); + AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, float radius, const AZ::Vector3& viewPos); - /// Used for interaction with spline primitive - it will generate a spline bound - /// to be interacted with and will display the intersection point on the spline - /// where a user may wish to insert a point. - class ManipulatorViewSplineSelect - : public ManipulatorView + //! Used for interaction with spline primitive - it will generate a spline bound + //! to be interacted with and will display the intersection point on the spline + //! where a user may wish to insert a point. + class ManipulatorViewSplineSelect : public ManipulatorView { public: AZ_CLASS_ALLOCATOR(ManipulatorViewSplineSelect, AZ::SystemAllocator, 0) AZ_RTTI(ManipulatorViewSplineSelect, "{60996E49-D6BF-4817-BAA3-D27A407DD21A}", ManipulatorView) void Draw( - ManipulatorManagerId managerId, const ManipulatorManagerState& managerState, - ManipulatorId manipulatorId, const ManipulatorState& manipulatorState, - AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState, + ManipulatorManagerId managerId, + const ManipulatorManagerState& managerState, + ManipulatorId manipulatorId, + const ManipulatorState& manipulatorState, + AzFramework::DebugDisplayRequests& debugDisplay, + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; AZStd::weak_ptr m_spline; @@ -343,65 +362,61 @@ namespace AzToolsFramework AZ::Color m_color = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); }; - /// Returns true if axis is pointing away from us (we should flip it). + //! Returns true if axis is pointing away from us (we should flip it). inline bool ShouldFlipCameraAxis( - const AZ::Transform& worldFromLocal, const AZ::Vector3& localPosition, - const AZ::Vector3& axis, const AzFramework::CameraState& cameraState) + const AZ::Transform& worldFromLocal, + const AZ::Vector3& localPosition, + const AZ::Vector3& axis, + const AzFramework::CameraState& cameraState) { - return (worldFromLocal.TransformPoint(localPosition) - cameraState.m_position).Dot( - TransformDirectionNoScaling(worldFromLocal, axis)) > 0.0f; + return (worldFromLocal.TransformPoint(localPosition) - cameraState.m_position) + .Dot(TransformDirectionNoScaling(worldFromLocal, axis)) > 0.0f; } - /// @brief Return the world transform of the entity with uniform scale - choose - /// the largest element. + //! @brief Return the world transform of the entity with uniform scale - choose + //! the largest element. AZ::Transform WorldFromLocalWithUniformScale(AZ::EntityId entityId); - /// Get the non-uniform scale for this entity id. + //! Get the non-uniform scale for this entity id. AZ::Vector3 GetNonUniformScale(AZ::EntityId entityId); // Helpers to create various manipulator views. AZStd::unique_ptr CreateManipulatorViewQuad( - const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, - const AZ::Color& axis2Color, float size); + const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, float size); - AZStd::unique_ptr CreateManipulatorViewQuadBillboard( - const AZ::Color& color, float size); + AZStd::unique_ptr CreateManipulatorViewQuadBillboard(const AZ::Color& color, float size); AZStd::unique_ptr CreateManipulatorViewLine( - const LinearManipulator& linearManipulator, const AZ::Color& color, - float length, float width); + const LinearManipulator& linearManipulator, const AZ::Color& color, float length, float width); AZStd::unique_ptr CreateManipulatorViewLineSelect( - const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color, - float width); + const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color, float width); AZStd::unique_ptr CreateManipulatorViewCone( - const LinearManipulator& linearManipulator, const AZ::Color& color, - const AZ::Vector3& offset, float length, float radius); + const LinearManipulator& linearManipulator, const AZ::Color& color, const AZ::Vector3& offset, float length, float radius); AZStd::unique_ptr CreateManipulatorViewBox( - const AZ::Transform& transform, const AZ::Color& color, - const AZ::Vector3& offset, const AZ::Vector3& halfExtents); + const AZ::Transform& transform, const AZ::Color& color, const AZ::Vector3& offset, const AZ::Vector3& halfExtents); AZStd::unique_ptr CreateManipulatorViewCylinder( - const LinearManipulator& linearManipulator, const AZ::Color& color, - float length, float radius); + const LinearManipulator& linearManipulator, const AZ::Color& color, float length, float radius); AZStd::unique_ptr CreateManipulatorViewSphere( const AZ::Color& color, float radius, const DecideColorFn& decideColor, bool enableDepthTest = false); AZStd::unique_ptr CreateManipulatorViewCircle( - const AngularManipulator& angularManipulator, const AZ::Color& color, - float radius, float width, ManipulatorViewCircle::DrawCircleFunc drawFunc); + const AngularManipulator& angularManipulator, + const AZ::Color& color, + float radius, + float width, + ManipulatorViewCircle::DrawCircleFunc drawFunc); AZStd::unique_ptr CreateManipulatorViewSplineSelect( - const SplineSelectionManipulator& splineManipulator, const AZ::Color& color, - float width); + const SplineSelectionManipulator& splineManipulator, const AZ::Color& color, float width); - /// Returns the vector between the view (camera) and the manipulator in the space - /// of the Manipulator (manipulator space + local transform). - AZ::Vector3 CalculateViewDirection( - const Manipulators& manipulators, const AZ::Vector3& worldViewPosition); + //! Returns the vector between the view (camera) and the manipulator in the space + //! of the Manipulator (manipulator space + local transform). + AZ::Vector3 CalculateViewDirection(const Manipulators& manipulators, const AZ::Vector3& worldViewPosition); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp index 83c4c28e9a..922ac95bf7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "MultiLinearManipulator.h" @@ -56,10 +56,13 @@ namespace AzToolsFramework } static MultiLinearManipulator::Action BuildMultiLinearManipulatorAction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const AZStd::vector& fixedAxes, - const AZStd::vector& starterStates, const GridSnapParameters& gridSnapParams) + const AZStd::vector& starterStates, + const GridSnapParameters& gridSnapParams) { MultiLinearManipulator::Action action; action.m_viewportId = interaction.m_interactionId.m_viewportId; @@ -96,8 +99,8 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); // pass action containing all linear actions for each axis to handler m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction( - worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapParams)); + worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters, + gridSnapParams)); } } @@ -108,8 +111,8 @@ namespace AzToolsFramework const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); m_onMouseMoveCallback(BuildMultiLinearManipulatorAction( - worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapParams)); + worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters, + gridSnapParams)); } } @@ -120,8 +123,8 @@ namespace AzToolsFramework const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction( - worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), - interaction, m_fixedAxes, m_starters, gridSnapParams)); + worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters, + gridSnapParams)); m_starters.clear(); } @@ -138,36 +141,31 @@ namespace AzToolsFramework const AZ::Transform combined = TransformUniformScale(GetSpace()) * GetLocalTransform(); for (const auto& fixed : m_fixedAxes) { - DrawAxis( - debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, fixed.m_axis)); + DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, fixed.m_axis)); } } for (auto& view : m_manipulatorViews) { view->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - ApplySpace(GetLocalTransform()), GetNonUniformScale(), - AZ::Vector3::CreateZero(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } void MultiLinearManipulator::AddAxis(const AZ::Vector3& axis) { - m_fixedAxes.push_back(LinearManipulator::Fixed{axis}); + m_fixedAxes.push_back(LinearManipulator::Fixed{ axis }); } void MultiLinearManipulator::AddAxes(const AZStd::vector& axes) { AZStd::transform( - axes.begin(), axes.end(), - AZStd::back_inserter(m_fixedAxes), + axes.begin(), axes.end(), AZStd::back_inserter(m_fixedAxes), [](const AZ::Vector3& axis) { - return LinearManipulator::Fixed{axis}; + return LinearManipulator::Fixed{ axis }; }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h index 8e31e02605..7cae803dfa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/MultiLinearManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -80,12 +80,9 @@ namespace AzToolsFramework } private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; - void OnMouseMoveImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; + void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp index 6eb96f081c..f146ca4430 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "PlanarManipulator.h" @@ -22,12 +22,15 @@ namespace AzToolsFramework { PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, - const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance) + const Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const ViewportInteraction::MouseInteraction& interaction, + const float intersectionDistance) { - const ManipulatorInteraction manipulatorInteraction = - BuildManipulatorInteraction( - worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); + const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( + worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal); @@ -37,8 +40,8 @@ namespace AzToolsFramework StartInternal startInternal; Internal::CalculateRayPlaneIntersectingPoint( - manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, - localIntersectionPoint, normal, startInternal.m_localHitPosition); + manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint, normal, + startInternal.m_localHitPosition); startInternal.m_localPosition = localTransform.GetTranslation(); @@ -46,13 +49,16 @@ namespace AzToolsFramework } PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, + const Fixed& fixed, + const StartInternal& startInternal, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction) { - const ManipulatorInteraction manipulatorInteraction = - BuildManipulatorInteraction( - worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); + const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction( + worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection); const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal); @@ -61,8 +67,8 @@ namespace AzToolsFramework // if an invalid ray intersection is attempted AZ::Vector3 localHitPosition = startInternal.m_localHitPosition; Internal::CalculateRayPlaneIntersectingPoint( - manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, - startInternal.m_localHitPosition, normal, localHitPosition); + manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, startInternal.m_localHitPosition, normal, + localHitPosition); localHitPosition = Internal::TryConstrainHitPositionToView( localHitPosition, startInternal.m_localHitPosition, worldFromLocal.GetInverse(), @@ -126,8 +132,8 @@ namespace AzToolsFramework const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace()); m_startInternal = CalculateManipulationDataStart( - m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), - interaction, rayIntersectionDistance); + m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), interaction, + rayIntersectionDistance); if (m_onLeftMouseDownCallback) { @@ -180,9 +186,10 @@ namespace AzToolsFramework // display the exact hit (ray intersection) of the mouse pick on the manipulator DrawTransformAxes( - debugDisplay, TransformUniformScale(GetSpace()) * - AZ::Transform::CreateTranslation( - action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localOffset)); + debugDisplay, + TransformUniformScale(GetSpace()) * + AZ::Transform::CreateTranslation( + action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localOffset)); } AZ::Transform combined = GetLocalTransform(); @@ -191,23 +198,16 @@ namespace AzToolsFramework DrawTransformAxes(debugDisplay, combined); - DrawAxis( - debugDisplay, combined.GetTranslation(), - TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis1)); - DrawAxis( - debugDisplay, combined.GetTranslation(), - TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis2)); + DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis1)); + DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis2)); } for (auto& view : m_manipulatorViews) { view->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - ApplySpace(GetLocalTransform()), GetNonUniformScale(), - AZ::Vector3::CreateZero(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h index 154ed4c7d6..3bd028ec0a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/PlanarManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -23,13 +23,13 @@ namespace AzToolsFramework class ManipulatorView; struct GridSnapParameters; - /// PlanarManipulator serves as a visual tool for users to modify values - /// in two dimension in a plane defined two non-collinear axes in 3D space. + //! PlanarManipulator serves as a visual tool for users to modify values + //! in two dimension in a plane defined two non-collinear axes in 3D space. class PlanarManipulator : public BaseManipulator , public ManipulatorSpaceWithLocalTransform { - /// Private constructor. + //! Private constructor. explicit PlanarManipulator(const AZ::Transform& worldFromLocal); public: @@ -42,43 +42,51 @@ namespace AzToolsFramework ~PlanarManipulator() = default; - /// A Manipulator must only be created and managed through a shared_ptr. + //! A Manipulator must only be created and managed through a shared_ptr. static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal); - /// Unchanging data set once for the planar manipulator. + //! Unchanging data set once for the planar manipulator. struct Fixed { - AZ::Vector3 m_axis1 = AZ::Vector3::CreateAxisX(); ///< m_axis1 and m_axis2 have to be orthogonal, they together define a plane in 3d space. + AZ::Vector3 m_axis1 = + AZ::Vector3::CreateAxisX(); //!< m_axis1 and m_axis2 have to be orthogonal, they together define a plane in 3d space. AZ::Vector3 m_axis2 = AZ::Vector3::CreateAxisY(); - AZ::Vector3 m_normal = AZ::Vector3::CreateAxisZ(); ///< m_normal is calculated automatically when setting the axes. + AZ::Vector3 m_normal = AZ::Vector3::CreateAxisZ(); //!< m_normal is calculated automatically when setting the axes. }; - /// The state of the manipulator at the start of an interaction. + //! The state of the manipulator at the start of an interaction. struct Start { - AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. - AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens. + AZ::Vector3 m_localPosition; //!< The current position of the manipulator in local space. + AZ::Vector3 m_localHitPosition; //!< The intersection point in local space between the ray and the manipulator when the mouse + //!< down event happens. }; - /// The state of the manipulator during an interaction. + //! The state of the manipulator during an interaction. struct Current { - AZ::Vector3 m_localOffset; ///< The current position of the manipulator in local space. + AZ::Vector3 m_localOffset; //!< The current position of the manipulator in local space. }; - /// Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). + //! Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). struct Action { Fixed m_fixed; Start m_start; Current m_current; ViewportInteraction::KeyboardModifiers m_modifiers; - AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localOffset; } - AZ::Vector3 LocalPositionOffset() const { return m_current.m_localOffset; } + AZ::Vector3 LocalPosition() const + { + return m_start.m_localPosition + m_current.m_localOffset; + } + AZ::Vector3 LocalPositionOffset() const + { + return m_current.m_localOffset; + } }; - /// This is the function signature of callbacks that will be invoked whenever a manipulator - /// is being clicked on or dragged. + //! This is the function signature of callbacks that will be invoked whenever a manipulator + //! is being clicked on or dragged. using MouseActionCallback = AZStd::function; void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback); @@ -91,11 +99,17 @@ namespace AzToolsFramework const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; - /// Ensure @param axis1 and @param axis2 are not collinear. + //! Ensure @param axis1 and @param axis2 are not collinear. void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2); - const AZ::Vector3& GetAxis1() const { return m_fixed.m_axis1; } - const AZ::Vector3& GetAxis2() const { return m_fixed.m_axis2; } + const AZ::Vector3& GetAxis1() const + { + return m_fixed.m_axis1; + } + const AZ::Vector3& GetAxis2() const + { + return m_fixed.m_axis2; + } template void SetViews(Views&& views) @@ -104,21 +118,19 @@ namespace AzToolsFramework } private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; - void OnMouseMoveImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; + void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; - /// Initial data recorded when a press first happens with a planar manipulator. + //! Initial data recorded when a press first happens with a planar manipulator. struct StartInternal { - AZ::Vector3 m_localPosition; ///< The starting position of the manipulator in local space. - AZ::Vector3 m_localHitPosition; ///< The intersection point in world space between the ray and the manipulator when the mouse down event happens. + AZ::Vector3 m_localPosition; //!< The starting position of the manipulator in local space. + AZ::Vector3 m_localHitPosition; //!< The intersection point in world space between the ray and the manipulator when the mouse + //!< down event happens. }; Fixed m_fixed; @@ -128,15 +140,23 @@ namespace AzToolsFramework MouseActionCallback m_onLeftMouseUpCallback = nullptr; MouseActionCallback m_onMouseMoveCallback = nullptr; - ManipulatorViews m_manipulatorViews; ///< Look of manipulator. + ManipulatorViews m_manipulatorViews; //!< Look of manipulator. static StartInternal CalculateManipulationDataStart( - const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance); + const Fixed& fixed, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const ViewportInteraction::MouseInteraction& interaction, + float intersectionDistance); static Action CalculateManipulationDataAction( - const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, - const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams, + const Fixed& fixed, + const StartInternal& startInternal, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale, + const AZ::Transform& localTransform, + const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.cpp index 399bea4024..4bb39509e3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "RotationManipulators.h" @@ -28,8 +28,7 @@ namespace AzToolsFramework m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal); } - void RotationManipulators::InstallLeftMouseDownCallback( - const AngularManipulator::MouseActionCallback& onMouseDownCallback) + void RotationManipulators::InstallLeftMouseDownCallback(const AngularManipulator::MouseActionCallback& onMouseDownCallback) { for (AZStd::shared_ptr& manipulator : m_localAngularManipulators) { @@ -39,8 +38,7 @@ namespace AzToolsFramework m_viewAngularManipulator->InstallLeftMouseDownCallback(onMouseDownCallback); } - void RotationManipulators::InstallMouseMoveCallback( - const AngularManipulator::MouseActionCallback& onMouseMoveCallback) + void RotationManipulators::InstallMouseMoveCallback(const AngularManipulator::MouseActionCallback& onMouseMoveCallback) { for (AZStd::shared_ptr& manipulator : m_localAngularManipulators) { @@ -50,8 +48,7 @@ namespace AzToolsFramework m_viewAngularManipulator->InstallMouseMoveCallback(onMouseMoveCallback); } - void RotationManipulators::InstallLeftMouseUpCallback( - const AngularManipulator::MouseActionCallback& onMouseUpCallback) + void RotationManipulators::InstallLeftMouseUpCallback(const AngularManipulator::MouseActionCallback& onMouseUpCallback) { for (AZStd::shared_ptr& manipulator : m_localAngularManipulators) { @@ -109,14 +106,13 @@ namespace AzToolsFramework m_viewAngularManipulator->SetSpace(worldFromLocal); } - void RotationManipulators::SetLocalAxes( - const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3) + void RotationManipulators::SetLocalAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3) { const AZ::Vector3 axes[] = { axis1, axis2, axis3 }; for (size_t manipulatorIndex = 0; manipulatorIndex < m_localAngularManipulators.size(); ++manipulatorIndex) { - m_localAngularManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]); + m_localAngularManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]); } } @@ -124,34 +120,25 @@ namespace AzToolsFramework { m_viewAngularManipulator->SetAxis(axis); - if (auto circleView = azrtti_cast( - m_viewAngularManipulator->GetView())) + if (auto circleView = azrtti_cast(m_viewAngularManipulator->GetView())) { circleView->m_axis = axis; } } void RotationManipulators::ConfigureView( - const float radius, const AZ::Color& axis1Color, - const AZ::Color& axis2Color, const AZ::Color& axis3Color) + const float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color) { - const AZ::Color colors[] = { - axis1Color, axis2Color, axis3Color - }; + const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color }; for (size_t manipulatorIndex = 0; manipulatorIndex < m_localAngularManipulators.size(); ++manipulatorIndex) { - m_localAngularManipulators[manipulatorIndex]->SetView( - CreateManipulatorViewCircle( - *m_localAngularManipulators[manipulatorIndex], colors[manipulatorIndex], - radius, 0.05f, DrawHalfDottedCircle)); + m_localAngularManipulators[manipulatorIndex]->SetView(CreateManipulatorViewCircle( + *m_localAngularManipulators[manipulatorIndex], colors[manipulatorIndex], radius, 0.05f, DrawHalfDottedCircle)); } - m_viewAngularManipulator->SetView( - CreateManipulatorViewCircle( - *m_viewAngularManipulator, - AZ::Color(1.0f, 1.0f, 1.0f, 1.0f), - radius + (radius * 0.12f), 0.05f, DrawFullCircle)); + m_viewAngularManipulator->SetView(CreateManipulatorViewCircle( + *m_viewAngularManipulator, AZ::Color(1.0f, 1.0f, 1.0f, 1.0f), radius + (radius * 0.12f), 0.05f, DrawFullCircle)); } bool RotationManipulators::PerformingActionViewAxis() const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.h index 11b6e0838c..5ecfa21f26 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/RotationManipulators.h @@ -1,27 +1,26 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once #include -#include #include +#include namespace AzToolsFramework { - /// RotationManipulators is an aggregation of 3 angular manipulators who share the same origin - /// in addition to a view aligned angular manipulator (facing the camera). - class RotationManipulators - : public Manipulators + //! RotationManipulators is an aggregation of 3 angular manipulators who share the same origin + //! in addition to a view aligned angular manipulator (facing the camera). + class RotationManipulators : public Manipulators { public: AZ_RTTI(RotationManipulators, "{5D1F1D47-1D5B-4E42-B47E-23F108F8BF7D}") @@ -40,12 +39,10 @@ namespace AzToolsFramework void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override; void RefreshView(const AZ::Vector3& worldViewPosition) override; - void SetLocalAxes( - const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3); + void SetLocalAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3); void SetViewAxis(const AZ::Vector3& axis); - void ConfigureView( - float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color); + void ConfigureView(float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color); bool PerformingActionViewAxis() const; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.cpp index caeedd834f..079fde669a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ScaleManipulators.h" @@ -28,8 +28,7 @@ namespace AzToolsFramework m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal); } - void ScaleManipulators::InstallAxisLeftMouseDownCallback( - const LinearManipulator::MouseActionCallback& onMouseDownCallback) + void ScaleManipulators::InstallAxisLeftMouseDownCallback(const LinearManipulator::MouseActionCallback& onMouseDownCallback) { for (AZStd::shared_ptr& manipulator : m_axisScaleManipulators) { @@ -37,8 +36,7 @@ namespace AzToolsFramework } } - void ScaleManipulators::InstallAxisMouseMoveCallback( - const LinearManipulator::MouseActionCallback& onMouseMoveCallback) + void ScaleManipulators::InstallAxisMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback) { for (AZStd::shared_ptr& manipulator : m_axisScaleManipulators) { @@ -46,8 +44,7 @@ namespace AzToolsFramework } } - void ScaleManipulators::InstallAxisLeftMouseUpCallback( - const LinearManipulator::MouseActionCallback& onMouseUpCallback) + void ScaleManipulators::InstallAxisLeftMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback) { for (AZStd::shared_ptr& manipulator : m_axisScaleManipulators) { @@ -55,22 +52,19 @@ namespace AzToolsFramework } } - void ScaleManipulators::InstallUniformLeftMouseDownCallback( - const LinearManipulator::MouseActionCallback& onMouseDownCallback) + void ScaleManipulators::InstallUniformLeftMouseDownCallback(const LinearManipulator::MouseActionCallback& onMouseDownCallback) { m_uniformScaleManipulator->InstallLeftMouseDownCallback(onMouseDownCallback); } - void ScaleManipulators::InstallUniformMouseMoveCallback( - const LinearManipulator::MouseActionCallback& onMouseMoveCallback) + void ScaleManipulators::InstallUniformMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback) { - m_uniformScaleManipulator->InstallMouseMoveCallback(onMouseMoveCallback); + m_uniformScaleManipulator->InstallMouseMoveCallback(onMouseMoveCallback); } - void ScaleManipulators::InstallUniformLeftMouseUpCallback( - const LinearManipulator::MouseActionCallback& onMouseUpCallback) + void ScaleManipulators::InstallUniformLeftMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback) { - m_uniformScaleManipulator->InstallLeftMouseUpCallback(onMouseUpCallback); + m_uniformScaleManipulator->InstallLeftMouseUpCallback(onMouseUpCallback); } void ScaleManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform) @@ -80,8 +74,7 @@ namespace AzToolsFramework manipulator->SetLocalTransform(localTransform); } - m_uniformScaleManipulator->SetVisualOrientationOverride( - QuaternionFromTransformNoScaling(localTransform)); + m_uniformScaleManipulator->SetVisualOrientationOverride(QuaternionFromTransformNoScaling(localTransform)); m_uniformScaleManipulator->SetLocalOrientation(AZ::Quaternion::CreateIdentity()); } @@ -113,14 +106,13 @@ namespace AzToolsFramework m_uniformScaleManipulator->SetSpace(worldFromLocal); } - void ScaleManipulators::SetAxes( - const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3) + void ScaleManipulators::SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3) { - AZ::Vector3 axes[] = { axis1, axis2, axis3 }; + AZ::Vector3 axes[] = { axis1, axis2, axis3 }; for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex) { - m_axisScaleManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]); + m_axisScaleManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]); } // uniform scale manipulator uses Z axis for scaling (always in world space) @@ -129,32 +121,27 @@ namespace AzToolsFramework } void ScaleManipulators::ConfigureView( - const float axisLength, const AZ::Color& axis1Color, - const AZ::Color& axis2Color, const AZ::Color& axis3Color) + const float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color) { const float boxSize = 0.1f; const float lineWidth = 0.05f; - const AZ::Color colors[] = { - axis1Color, axis2Color, axis3Color - }; + const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color }; for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex) { ManipulatorViews views; - views.emplace_back(CreateManipulatorViewLine( - *m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, lineWidth)); + views.emplace_back( + CreateManipulatorViewLine(*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, lineWidth)); views.emplace_back(CreateManipulatorViewBox( AZ::Transform::CreateIdentity(), colors[manipulatorIndex], - m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (axisLength - boxSize), - AZ::Vector3(boxSize))); + m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (axisLength - boxSize), AZ::Vector3(boxSize))); m_axisScaleManipulators[manipulatorIndex]->SetViews(AZStd::move(views)); } ManipulatorViews views; views.emplace_back(CreateManipulatorViewBox( - AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), - AZ::Vector3::CreateZero(), AZ::Vector3(boxSize))); + AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxSize))); m_uniformScaleManipulator->SetViews(AZStd::move(views)); } @@ -167,4 +154,4 @@ namespace AzToolsFramework manipulatorFn(m_uniformScaleManipulator.get()); } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.h index 24df3cda7b..b06d8f92c5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/ScaleManipulators.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -17,11 +17,10 @@ namespace AzToolsFramework { - /// ScaleManipulators is an aggregation of 3 linear manipulators for each basis axis who share - /// the same transform, and a single linear manipulator at the center of the transform whose - /// axis is world up (z). - class ScaleManipulators - : public Manipulators + //! ScaleManipulators is an aggregation of 3 linear manipulators for each basis axis who share + //! the same transform, and a single linear manipulator at the center of the transform whose + //! axis is world up (z). + class ScaleManipulators : public Manipulators { public: AZ_RTTI(ScaleManipulators, "{C6350CE0-7B7A-46F8-B65F-D4A54DD9A7D9}") @@ -42,16 +41,9 @@ namespace AzToolsFramework void SetLocalPositionImpl(const AZ::Vector3& localPosition) override; void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override; - void SetAxes( - const AZ::Vector3& axis1, - const AZ::Vector3& axis2, - const AZ::Vector3& axis3); + void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3); - void ConfigureView( - float axisLength, - const AZ::Color& axis1Color, - const AZ::Color& axis2Color, - const AZ::Color& axis3Color); + void ConfigureView(float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color); private: AZ_DISABLE_COPY_MOVE(ScaleManipulators) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp index 4925651580..3071ca74ae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "SelectionManipulator.h" @@ -16,8 +16,8 @@ namespace AzToolsFramework { - AZStd::shared_ptr SelectionManipulator::MakeShared(const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale) + AZStd::shared_ptr SelectionManipulator::MakeShared( + const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale) { return AZStd::shared_ptr(aznew SelectionManipulator(worldFromLocal, nonUniformScale)); } @@ -93,12 +93,9 @@ namespace AzToolsFramework for (auto& view : m_manipulatorViews) { view->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - TransformUniformScale(GetSpace()), GetNonUniformScale(), - GetLocalPosition(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState, + mouseInteraction); } } @@ -117,4 +114,4 @@ namespace AzToolsFramework view->Invalidate(GetManipulatorManagerId()); } } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.h index 1ae6ceb729..b862dfd684 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SelectionManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -20,13 +20,13 @@ namespace AzToolsFramework { class ManipulatorView; - /// Represents a sphere that can be clicked on to trigger a particular behavior - /// For example clicking a preview point to create a translation manipulator. + //! Represents a sphere that can be clicked on to trigger a particular behavior. + //! For example clicking a preview point to create a translation manipulator. class SelectionManipulator : public BaseManipulator , public ManipulatorSpaceWithLocalPosition { - /// Private constructor. + //! Private constructor. SelectionManipulator(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()); public: @@ -39,12 +39,12 @@ namespace AzToolsFramework ~SelectionManipulator() = default; - /// A Manipulator must only be created and managed through a shared_ptr. - static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal, - const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()); + //! A Manipulator must only be created and managed through a shared_ptr. + static AZStd::shared_ptr MakeShared( + const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne()); - /// This is the function signature of callbacks that will be invoked - /// whenever a selection manipulator is clicked on. + //! This is the function signature of callbacks that will be invoked + //! whenever a selection manipulator is clicked on. using MouseActionCallback = AZStd::function; void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback); @@ -58,10 +58,25 @@ namespace AzToolsFramework const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; - bool Selected() const { return m_selected; } - void Select() { m_selected = true; } - void Deselect() { m_selected = false; } - void ToggleSelected() { m_selected = !m_selected; } + bool Selected() const + { + return m_selected; + } + + void Select() + { + m_selected = true; + } + + void Deselect() + { + m_selected = false; + } + + void ToggleSelected() + { + m_selected = !m_selected; + } template void SetViews(Views&& views) @@ -70,13 +85,9 @@ namespace AzToolsFramework } private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, - float rayIntersectionDistance) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; - void OnRightMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, - float rayIntersectionDistance) override; + void OnRightMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; @@ -89,6 +100,6 @@ namespace AzToolsFramework MouseActionCallback m_onRightMouseDownCallback = nullptr; MouseActionCallback m_onRightMouseUpCallback = nullptr; - ManipulatorViews m_manipulatorViews; ///< Look of manipulator. + ManipulatorViews m_manipulatorViews; //!< Look of manipulator. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.cpp index 43fbbce80b..98972bcf33 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "SplineHoverSelection.h" @@ -20,11 +20,12 @@ namespace AzToolsFramework { - static const AZ::Color s_splineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); + static const AZ::Color SplineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f); SplineHoverSelection::SplineHoverSelection( const AZ::EntityComponentIdPair& entityComponentIdPair, - const ManipulatorManagerId managerId, const AZStd::shared_ptr& spline) + const ManipulatorManagerId managerId, + const AZStd::shared_ptr& spline) { m_splineSelectionManipulator = SplineSelectionManipulator::MakeShared(); m_splineSelectionManipulator->Register(managerId); @@ -33,16 +34,14 @@ namespace AzToolsFramework const float splineWidth = 0.05f; m_splineSelectionManipulator->SetSpline(spline); - m_splineSelectionManipulator->SetView(CreateManipulatorViewSplineSelect( - *m_splineSelectionManipulator, s_splineSelectManipulatorColor, splineWidth)); + m_splineSelectionManipulator->SetView( + CreateManipulatorViewSplineSelect(*m_splineSelectionManipulator, SplineSelectManipulatorColor, splineWidth)); m_splineSelectionManipulator->InstallLeftMouseUpCallback( [entityComponentIdPair](const SplineSelectionManipulator::Action& action) - { - InsertVertexAfter( - entityComponentIdPair, action.m_splineAddress.m_segmentIndex, - action.m_localSplineHitPosition); - }); + { + InsertVertexAfter(entityComponentIdPair, action.m_splineAddress.m_segmentIndex, action.m_localSplineHitPosition); + }); } SplineHoverSelection::~SplineHoverSelection() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.h index 11b10f8516..d8dcd573af 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineHoverSelection.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -19,20 +19,20 @@ namespace AZ { class Spline; class EntityComponentIdPair; -} +} // namespace AZ namespace AzToolsFramework { class SplineSelectionManipulator; - /// SplineHoverSelection is a concrete implementation of HoverSelection wrapping a Spline and - /// SplineManipulator. The underlying manipulators are used to control selection. - class SplineHoverSelection - : public HoverSelection + //! SplineHoverSelection is a concrete implementation of HoverSelection wrapping a Spline and + //! SplineManipulator. The underlying manipulators are used to control selection. + class SplineHoverSelection : public HoverSelection { public: explicit SplineHoverSelection( - const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId, + const AZ::EntityComponentIdPair& entityComponentIdPair, + ManipulatorManagerId managerId, const AZStd::shared_ptr& spline); SplineHoverSelection(const SplineHoverSelection&) = delete; SplineHoverSelection& operator=(const SplineHoverSelection&) = delete; @@ -46,6 +46,6 @@ namespace AzToolsFramework void SetNonUniformScale(const AZ::Vector3& nonUniformScale) override; private: - AZStd::shared_ptr m_splineSelectionManipulator; ///< Manipulator for adding points to spline. + AZStd::shared_ptr m_splineSelectionManipulator; //!< Manipulator for adding points to spline. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp index 5bfccefe48..39dbcb67fa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "SplineSelectionManipulator.h" @@ -18,8 +18,10 @@ namespace AzToolsFramework { SplineSelectionManipulator::Action CalculateManipulationDataAction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& rayOrigin, - const AZ::Vector3& rayDirection, const AZStd::weak_ptr& spline) + const AZ::Transform& worldFromLocal, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZStd::weak_ptr& spline) { SplineSelectionManipulator::Action action; if (const AZStd::shared_ptr splinePtr = spline.lock()) @@ -65,9 +67,7 @@ namespace AzToolsFramework if (m_onLeftMouseDownCallback) { m_onLeftMouseDownCallback(CalculateManipulationDataAction( - TransformUniformScale(GetSpace()), - interaction.m_mousePick.m_rayOrigin, - interaction.m_mousePick.m_rayDirection, m_spline)); + TransformUniformScale(GetSpace()), interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, m_spline)); } } @@ -76,9 +76,7 @@ namespace AzToolsFramework if (MouseOver() && m_onLeftMouseUpCallback) { m_onLeftMouseUpCallback(CalculateManipulationDataAction( - TransformUniformScale(GetSpace()), - interaction.m_mousePick.m_rayOrigin, - interaction.m_mousePick.m_rayDirection, m_spline)); + TransformUniformScale(GetSpace()), interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, m_spline)); } } @@ -99,12 +97,9 @@ namespace AzToolsFramework if (mouseInteraction.m_keyboardModifiers.Ctrl() && !mouseInteraction.m_keyboardModifiers.Shift()) { m_manipulatorView->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - TransformUniformScale(GetSpace()), GetNonUniformScale(), - AZ::Vector3::CreateZero(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, + cameraState, mouseInteraction); } } @@ -122,4 +117,4 @@ namespace AzToolsFramework { m_manipulatorView->Invalidate(GetManipulatorManagerId()); } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.h index 721c3413ef..e1a2fe26ab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SplineSelectionManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -23,13 +23,13 @@ namespace AzToolsFramework { class ManipulatorView; - /// A manipulator to represent selection of a spline. Underlying spline data is - /// used to test mouse picking ray against to preview closest point on spline. + //! A manipulator to represent selection of a spline. Underlying spline data is + //! used to test mouse picking ray against to preview closest point on spline. class SplineSelectionManipulator : public BaseManipulator , public ManipulatorSpace { - /// Private constructor. + //! Private constructor. SplineSelectionManipulator(); public: @@ -41,10 +41,10 @@ namespace AzToolsFramework ~SplineSelectionManipulator(); - /// A Manipulator must only be created and managed through a shared_ptr. + //! A Manipulator must only be created and managed through a shared_ptr. static AZStd::shared_ptr MakeShared(); - /// Mouse action data used by MouseActionCallback. + //! Mouse action data used by MouseActionCallback. struct Action { AZ::Vector3 m_localSplineHitPosition; @@ -62,29 +62,36 @@ namespace AzToolsFramework const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteraction& mouseInteraction) override; - void SetSpline(AZStd::shared_ptr spline) { m_spline = AZStd::move(spline); } - AZStd::weak_ptr GetSpline() const { return m_spline; } + void SetSpline(AZStd::shared_ptr spline) + { + m_spline = AZStd::move(spline); + } + AZStd::weak_ptr GetSpline() const + { + return m_spline; + } void SetView(AZStd::unique_ptr&& view); private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; AZStd::weak_ptr m_spline; - AZStd::unique_ptr m_manipulatorView = nullptr; ///< Look of manipulator and bounds for interaction. + AZStd::unique_ptr m_manipulatorView = nullptr; //!< Look of manipulator and bounds for interaction. MouseActionCallback m_onLeftMouseDownCallback = nullptr; MouseActionCallback m_onLeftMouseUpCallback = nullptr; - ViewportInteraction::KeyboardModifiers m_keyboardModifiers; ///< What modifier keys are pressed when interacting with this manipulator. + ViewportInteraction::KeyboardModifiers + m_keyboardModifiers; //!< What modifier keys are pressed when interacting with this manipulator. }; SplineSelectionManipulator::Action CalculateManipulationDataAction( - const AZ::Transform& worldFromLocal, const AZ::Vector3& rayOrigin, - const AZ::Vector3& rayDirection, const AZStd::weak_ptr& spline); + const AZ::Transform& worldFromLocal, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZStd::weak_ptr& spline); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp index f570c20a7e..aa3f3f5882 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "SurfaceManipulator.h" @@ -18,19 +18,22 @@ namespace AzToolsFramework { SurfaceManipulator::StartInternal SurfaceManipulator::CalculateManipulationDataStart( - const AZ::Transform& worldFromLocal, const AZ::Vector3& worldSurfacePosition, - const AZ::Vector3& localStartPosition, const bool snapping, const float gridSize, const int viewportId) + const AZ::Transform& worldFromLocal, + const AZ::Vector3& worldSurfacePosition, + const AZ::Vector3& localStartPosition, + const bool snapping, + const float gridSize, + const int viewportId) { const AZ::Transform worldFromLocalUniform = AzToolsFramework::TransformUniformScale(worldFromLocal); const AZ::Transform localFromWorldUniform = worldFromLocalUniform.GetInverse(); const AZ::Vector3 localFinalSurfacePosition = snapping - ? CalculateSnappedTerrainPosition( - // note: gridSize is not scaled by scaleRecip here as localStartPosition is - // unscaled itself so the position returned by CalculateSnappedTerrainPosition - // must be in the same space (if localStartPosition were also scaled, gridSize - // would need to be multiplied by scaleRecip) - worldSurfacePosition, worldFromLocalUniform, viewportId, gridSize) + // note: gridSize is not scaled by scaleRecip here as localStartPosition is + // unscaled itself so the position returned by CalculateSnappedTerrainPosition + // must be in the same space (if localStartPosition were also scaled, gridSize + // would need to be multiplied by scaleRecip) + ? CalculateSnappedTerrainPosition(worldSurfacePosition, worldFromLocalUniform, viewportId, gridSize) : localFromWorldUniform.TransformPoint(worldSurfacePosition); // delta/offset between initial vertex position and terrain pick position @@ -44,9 +47,13 @@ namespace AzToolsFramework } SurfaceManipulator::Action SurfaceManipulator::CalculateManipulationDataAction( - const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& worldSurfacePosition, const bool snapping, const float gridSize, - const ViewportInteraction::KeyboardModifiers keyboardModifiers, const int viewportId) + const StartInternal& startInternal, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& worldSurfacePosition, + const bool snapping, + const float gridSize, + const ViewportInteraction::KeyboardModifiers keyboardModifiers, + const int viewportId) { const AZ::Transform worldFromLocalUniform = AzToolsFramework::TransformUniformScale(worldFromLocal); const AZ::Transform localFromWorldUniform = worldFromLocalUniform.GetInverse(); @@ -54,8 +61,7 @@ namespace AzToolsFramework const float scaleRecip = ScaleReciprocal(worldFromLocalUniform); const AZ::Vector3 localFinalSurfacePosition = snapping - ? CalculateSnappedTerrainPosition( - worldSurfacePosition, worldFromLocalUniform, viewportId, gridSize * scaleRecip) + ? CalculateSnappedTerrainPosition(worldSurfacePosition, worldFromLocalUniform, viewportId, gridSize * scaleRecip) : localFromWorldUniform.TransformPoint(worldSurfacePosition); Action action; @@ -106,17 +112,14 @@ namespace AzToolsFramework interaction.m_mousePick.m_screenCoordinates); m_startInternal = CalculateManipulationDataStart( - worldFromLocalUniformScale, worldSurfacePosition, GetLocalPosition(), - gridSnapParams.m_gridSnap, gridSnapParams.m_gridSize, + worldFromLocalUniformScale, worldSurfacePosition, GetLocalPosition(), gridSnapParams.m_gridSnap, gridSnapParams.m_gridSize, interaction.m_interactionId.m_viewportId); if (m_onLeftMouseDownCallback) { m_onLeftMouseDownCallback(CalculateManipulationDataAction( - m_startInternal, worldFromLocalUniformScale, worldSurfacePosition, - gridSnapParams.m_gridSnap, gridSnapParams.m_gridSize, - interaction.m_keyboardModifiers, - interaction.m_interactionId.m_viewportId)); + m_startInternal, worldFromLocalUniformScale, worldSurfacePosition, gridSnapParams.m_gridSnap, gridSnapParams.m_gridSize, + interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId)); } } @@ -133,10 +136,8 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); m_onLeftMouseUpCallback(CalculateManipulationDataAction( - m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition, - gridSnapParams.m_gridSnap, - gridSnapParams.m_gridSize, - interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId)); + m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition, gridSnapParams.m_gridSnap, + gridSnapParams.m_gridSize, interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId)); } } @@ -153,10 +154,8 @@ namespace AzToolsFramework const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId); m_onMouseMoveCallback(CalculateManipulationDataAction( - m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition, - gridSnapParams.m_gridSnap, - gridSnapParams.m_gridSize, - interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId)); + m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition, gridSnapParams.m_gridSnap, + gridSnapParams.m_gridSize, interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId)); } } @@ -172,12 +171,9 @@ namespace AzToolsFramework const ViewportInteraction::MouseInteraction& mouseInteraction) { m_manipulatorView->Draw( - GetManipulatorManagerId(), managerState, - GetManipulatorId(), { - TransformUniformScale(GetSpace()), GetNonUniformScale(), - GetLocalPosition(), MouseOver() - }, - debugDisplay, cameraState, mouseInteraction); + GetManipulatorManagerId(), managerState, GetManipulatorId(), + { TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState, + mouseInteraction); } void SurfaceManipulator::InvalidateImpl() @@ -189,4 +185,4 @@ namespace AzToolsFramework { m_manipulatorView = AZStd::move(view); } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.h index 72eb3a5cda..6461954353 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/SurfaceManipulator.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -21,13 +21,13 @@ namespace AzToolsFramework { class ManipulatorView; - /// Surface manipulator will ensure the point(s) it controls snap precisely to the xy grid - /// while also staying aligned exactly to the height of the terrain. + //! Surface manipulator will ensure the point(s) it controls snap precisely to the xy grid + //! while also staying aligned exactly to the height of the terrain. class SurfaceManipulator : public BaseManipulator , public ManipulatorSpaceWithLocalPosition { - /// Private constructor. + //! Private constructor. explicit SurfaceManipulator(const AZ::Transform& worldFromLocal); public: @@ -40,30 +40,36 @@ namespace AzToolsFramework ~SurfaceManipulator() = default; - /// A Manipulator must only be created and managed through a shared_ptr. + //! A Manipulator must only be created and managed through a shared_ptr. static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal); - /// The state of the manipulator at the start of an interaction. + //! The state of the manipulator at the start of an interaction. struct Start { - AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. + AZ::Vector3 m_localPosition; //!< The current position of the manipulator in local space. + AZ::Vector3 m_snapOffset; //!< The snap offset amount to ensure manipulator is aligned to the grid. }; - /// The state of the manipulator during an interaction. + //! The state of the manipulator during an interaction. struct Current { - AZ::Vector3 m_localOffset; ///< The current offset of the manipulator from its starting position in local space. + AZ::Vector3 m_localOffset; //!< The current offset of the manipulator from its starting position in local space. }; - /// Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). + //! Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state). struct Action { Start m_start; Current m_current; ViewportInteraction::KeyboardModifiers m_modifiers; - AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localOffset; } - AZ::Vector3 LocalPositionOffset() const { return m_current.m_localOffset; } + AZ::Vector3 LocalPosition() const + { + return m_start.m_localPosition + m_current.m_localOffset; + } + AZ::Vector3 LocalPositionOffset() const + { + return m_current.m_localOffset; + } }; using MouseActionCallback = AZStd::function; @@ -81,39 +87,44 @@ namespace AzToolsFramework void SetView(AZStd::unique_ptr&& view); private: - void OnLeftMouseDownImpl( - const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; - void OnLeftMouseUpImpl( - const ViewportInteraction::MouseInteraction& interaction) override; - void OnMouseMoveImpl( - const ViewportInteraction::MouseInteraction& interaction) override; + void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override; + void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override; + void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override; void InvalidateImpl() override; void SetBoundsDirtyImpl() override; - /// Initial data recorded when a press first happens with a surface manipulator. + //! Initial data recorded when a press first happens with a surface manipulator. struct StartInternal { - AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space. - AZ::Vector3 m_localHitPosition; ///< The hit position with the terrain in local space. - AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid. + AZ::Vector3 m_localPosition; //!< The current position of the manipulator in local space. + AZ::Vector3 m_localHitPosition; //!< The hit position with the terrain in local space. + AZ::Vector3 m_snapOffset; //!< The snap offset amount to ensure manipulator is aligned to the grid. }; - StartInternal m_startInternal; ///< Internal initial state recorded/created in OnMouseDown. + StartInternal m_startInternal; //!< Internal initial state recorded/created in OnMouseDown. - AZStd::unique_ptr m_manipulatorView = nullptr; ///< Look of manipulator. + AZStd::unique_ptr m_manipulatorView = nullptr; //!< Look of manipulator. MouseActionCallback m_onLeftMouseDownCallback = nullptr; MouseActionCallback m_onLeftMouseUpCallback = nullptr; MouseActionCallback m_onMouseMoveCallback = nullptr; static StartInternal CalculateManipulationDataStart( - const AZ::Transform& worldFromLocal, const AZ::Vector3& worldSurfacePosition, - const AZ::Vector3& localPosition, bool snapping, float gridSize, int viewportId); + const AZ::Transform& worldFromLocal, + const AZ::Vector3& worldSurfacePosition, + const AZ::Vector3& localPosition, + bool snapping, + float gridSize, + int viewportId); static Action CalculateManipulationDataAction( - const StartInternal& startInternal, const AZ::Transform& worldFromLocal, - const AZ::Vector3& worldSurfacePosition, bool snapping, float gridSize, - ViewportInteraction::KeyboardModifiers keyboardModifiers, int viewportId); + const StartInternal& startInternal, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& worldSurfacePosition, + bool snapping, + float gridSize, + ViewportInteraction::KeyboardModifiers keyboardModifiers, + int viewportId); }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp index bfdfd8ba08..57d175c34e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "TranslationManipulators.h" @@ -77,8 +77,7 @@ namespace AzToolsFramework } } - void TranslationManipulators::InstallLinearManipulatorMouseUpCallback( - const LinearManipulator::MouseActionCallback& onMouseUpCallback) + void TranslationManipulators::InstallLinearManipulatorMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback) { for (AZStd::shared_ptr& manipulator : m_linearManipulators) { @@ -104,8 +103,7 @@ namespace AzToolsFramework } } - void TranslationManipulators::InstallPlanarManipulatorMouseUpCallback( - const PlanarManipulator::MouseActionCallback& onMouseUpCallback) + void TranslationManipulators::InstallPlanarManipulatorMouseUpCallback(const PlanarManipulator::MouseActionCallback& onMouseUpCallback) { for (AZStd::shared_ptr& manipulator : m_planarManipulators) { @@ -122,8 +120,7 @@ namespace AzToolsFramework } } - void TranslationManipulators::InstallSurfaceManipulatorMouseUpCallback( - const SurfaceManipulator::MouseActionCallback& onMouseUpCallback) + void TranslationManipulators::InstallSurfaceManipulatorMouseUpCallback(const SurfaceManipulator::MouseActionCallback& onMouseUpCallback) { if (m_surfaceManipulator) { @@ -242,7 +239,9 @@ namespace AzToolsFramework } void TranslationManipulators::ConfigureLinearView( - float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, + float axisLength, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, const AZ::Color& axis3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/) { const float coneLength = 0.28f; @@ -251,15 +250,13 @@ namespace AzToolsFramework const AZ::Color axesColor[] = { axis1Color, axis2Color, axis3Color }; - const auto configureLinearView = [lineWidth, coneLength, axisLength, coneRadius]( - LinearManipulator* linearManipulator, const AZ::Color& color) + const auto configureLinearView = + [lineWidth, coneLength, axisLength, coneRadius](LinearManipulator* linearManipulator, const AZ::Color& color) { ManipulatorViews views; - views.emplace_back(CreateManipulatorViewLine( - *linearManipulator, color, axisLength, lineWidth)); + views.emplace_back(CreateManipulatorViewLine(*linearManipulator, color, axisLength, lineWidth)); views.emplace_back(CreateManipulatorViewCone( - *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), - coneLength, coneRadius)); + *linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength), coneLength, coneRadius)); linearManipulator->SetViews(AZStd::move(views)); }; @@ -270,7 +267,8 @@ namespace AzToolsFramework } void TranslationManipulators::ConfigurePlanarView( - const AZ::Color& plane1Color, const AZ::Color& plane2Color /*= AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)*/, + const AZ::Color& plane1Color, + const AZ::Color& plane2Color /*= AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)*/, const AZ::Color& plane3Color /*= AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)*/) { const float planeSize = 0.6f; @@ -278,34 +276,29 @@ namespace AzToolsFramework for (size_t manipulatorIndex = 0; manipulatorIndex < m_planarManipulators.size(); ++manipulatorIndex) { - const AZStd::shared_ptr manipulatorView = - CreateManipulatorViewQuad( - *m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], - planesColor[(manipulatorIndex + 1) % 3], - planeSize); + const AZStd::shared_ptr manipulatorView = CreateManipulatorViewQuad( + *m_planarManipulators[manipulatorIndex], planesColor[manipulatorIndex], planesColor[(manipulatorIndex + 1) % 3], planeSize); - m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{manipulatorView}); + m_planarManipulators[manipulatorIndex]->SetViews(ManipulatorViews{ manipulatorView }); } } - void TranslationManipulators::ConfigureSurfaceView( - const float radius, const AZ::Color& color) + void TranslationManipulators::ConfigureSurfaceView(const float radius, const AZ::Color& color) { if (m_surfaceManipulator) { - m_surfaceManipulator->SetView(CreateManipulatorViewSphere(color, radius, - [](const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, - bool mouseOver, const AZ::Color& defaultColor) -> AZ::Color - { - const AZ::Color color[2] = + m_surfaceManipulator->SetView(CreateManipulatorViewSphere( + color, radius, + [](const ViewportInteraction::MouseInteraction& /*mouseInteraction*/, bool mouseOver, + const AZ::Color& defaultColor) -> AZ::Color { - defaultColor, - Vector3ToVector4( - BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), s_surfaceManipulatorTransparency) - }; + const AZ::Color color[2] = { + defaultColor, + Vector3ToVector4(BaseManipulator::s_defaultMouseOverColor.GetAsVector3(), s_surfaceManipulatorTransparency) + }; - return color[mouseOver]; - })); + return color[mouseOver]; + })); } } @@ -327,27 +320,17 @@ namespace AzToolsFramework } } - void ConfigureTranslationManipulatorAppearance3d( - TranslationManipulators* translationManipulators) + void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators) { - translationManipulators->SetAxes( - AZ::Vector3::CreateAxisX(), - AZ::Vector3::CreateAxisY(), - AZ::Vector3::CreateAxisZ()); - translationManipulators->ConfigurePlanarView( - s_xAxisColor, s_yAxisColor, s_zAxisColor); - translationManipulators->ConfigureLinearView( - s_axisLength, s_xAxisColor, s_yAxisColor, s_zAxisColor); - translationManipulators->ConfigureSurfaceView( - s_surfaceManipulatorRadius, s_surfaceManipulatorColor); + translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + translationManipulators->ConfigurePlanarView(s_xAxisColor, s_yAxisColor, s_zAxisColor); + translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor, s_zAxisColor); + translationManipulators->ConfigureSurfaceView(s_surfaceManipulatorRadius, s_surfaceManipulatorColor); } - void ConfigureTranslationManipulatorAppearance2d( - TranslationManipulators* translationManipulators) + void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators) { - translationManipulators->SetAxes( - AZ::Vector3::CreateAxisX(), - AZ::Vector3::CreateAxisY()); + translationManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY()); translationManipulators->ConfigurePlanarView(s_xAxisColor); translationManipulators->ConfigureLinearView(s_axisLength, s_xAxisColor, s_yAxisColor); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h index 0e7d3108aa..5f5f1a71e3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/TranslationManipulators.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -19,16 +19,15 @@ namespace AzToolsFramework { - /// TranslationManipulators is an aggregation of 3 linear manipulators, 3 planar manipulators - /// and one surface manipulator who share the same transform. - class TranslationManipulators - : public Manipulators + //! TranslationManipulators is an aggregation of 3 linear manipulators, 3 planar manipulators + //! and one surface manipulator who share the same transform. + class TranslationManipulators : public Manipulators { public: AZ_RTTI(TranslationManipulators, "{D5E49EA2-30E0-42BC-A51D-6A7F87818260}") AZ_CLASS_ALLOCATOR(TranslationManipulators, AZ::SystemAllocator, 0) - /// How many dimensions does this translation manipulator have + //! How many dimensions does this translation manipulator have. enum class Dimensions { Two, @@ -55,9 +54,7 @@ namespace AzToolsFramework void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override; void SetNonUniformScaleImpl(const AZ::Vector3& nonUniformScale) override; - void SetAxes( - const AZ::Vector3& axis1, const AZ::Vector3& axis2, - const AZ::Vector3& axis3 = AZ::Vector3::CreateAxisZ()); + void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3 = AZ::Vector3::CreateAxisZ()); void ConfigurePlanarView( const AZ::Color& plane1Color, @@ -66,11 +63,11 @@ namespace AzToolsFramework void ConfigureLinearView( float axisLength, - const AZ::Color& axis1Color, const AZ::Color& axis2Color, + const AZ::Color& axis1Color, + const AZ::Color& axis2Color, const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f)); - void ConfigureSurfaceView( - float radius, const AZ::Color& color); + void ConfigureSurfaceView(float radius, const AZ::Color& color); private: AZ_DISABLE_COPY_MOVE(TranslationManipulators) @@ -78,37 +75,43 @@ namespace AzToolsFramework // Manipulators void ProcessManipulators(const AZStd::function&) override; - const Dimensions m_dimensions; ///< How many dimensions of freedom does this manipulator have. + const Dimensions m_dimensions; //!< How many dimensions of freedom does this manipulator have. AZStd::vector> m_linearManipulators; AZStd::vector> m_planarManipulators; AZStd::shared_ptr m_surfaceManipulator = nullptr; }; - /// IndexedTranslationManipulator wraps a standard TranslationManipulators and allows it to be linked - /// to a particular index in a list of vertices/points. + //! IndexedTranslationManipulator wraps a standard TranslationManipulators and allows it to be linked + //! to a particular index in a list of vertices/points. template struct IndexedTranslationManipulator { explicit IndexedTranslationManipulator( - TranslationManipulators::Dimensions dimensions, AZ::u64 vertIndex, - const Vertex& position, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale) - : m_manipulator(dimensions, worldFromLocal, nonUniformScale) + TranslationManipulators::Dimensions dimensions, + AZ::u64 vertIndex, + const Vertex& position, + const AZ::Transform& worldFromLocal, + const AZ::Vector3& nonUniformScale) + : m_manipulator(dimensions, worldFromLocal, nonUniformScale) { m_vertices.push_back({ position, Vertex::CreateZero(), vertIndex }); } - /// Store vertex start position as manipulator event occurs, index refers to location in container. + //! Store vertex start position as manipulator event occurs, index refers to location in container. struct VertexLookup { Vertex m_start; Vertex m_offset; AZ::u64 m_index; - Vertex CurrentPosition() const { return m_start + m_offset; } + Vertex CurrentPosition() const + { + return m_start + m_offset; + } }; - /// Helper to iterate over all vertices stored by the manipulator. + //! Helper to iterate over all vertices stored by the manipulator. void Process(AZStd::function fn) { for (VertexLookup& vertex : m_vertices) @@ -117,16 +120,14 @@ namespace AzToolsFramework } } - AZStd::vector m_vertices; ///< List of vertices currently associated with this translation manipulator. + AZStd::vector m_vertices; //!< List of vertices currently associated with this translation manipulator. TranslationManipulators m_manipulator; }; - /// Function pointer to configure how a translation manipulator should look and behave (dimensions/axes/views). - using TranslationManipulatorConfiguratorFn = void(*)(TranslationManipulators*); + //! Function pointer to configure how a translation manipulator should look and behave (dimensions/axes/views). + using TranslationManipulatorConfiguratorFn = void (*)(TranslationManipulators*); - void ConfigureTranslationManipulatorAppearance3d( - TranslationManipulators* translationManipulators); - void ConfigureTranslationManipulatorAppearance2d( - TranslationManipulators* translationManipulators); + void ConfigureTranslationManipulatorAppearance3d(TranslationManipulators* translationManipulators); + void ConfigureTranslationManipulatorAppearance2d(TranslationManipulators* translationManipulators); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/BoundInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/BoundInterface.h index 3b579e889e..e8e822ca32 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/BoundInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/BoundInterface.h @@ -1,14 +1,15 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + #pragma once #include @@ -16,30 +17,44 @@ namespace AzToolsFramework { - /** - * Provide unique type alias for AZ::u64 for manipulator, bounds and manager. - */ + //! Provide unique type alias for AZ::u64 for manipulator, bounds and manager. template class IdType { public: explicit IdType(AZ::u64 id = 0) - : m_id(id) {} - operator AZ::u64() const { return m_id; } + : m_id(id) + { + } + + operator AZ::u64() const + { + return m_id; + } + + bool operator==(IdType other) const + { + return m_id == other.m_id; + } + + bool operator!=(IdType other) const + { + return m_id != other.m_id; + } - bool operator==(IdType other) const { return m_id == other.m_id; } - bool operator!=(IdType other) const { return m_id != other.m_id; } IdType& operator++() // pre-increment { ++m_id; return *this; } + IdType operator++(int) // post-increment { IdType temp = *this; ++*this; return temp; } + private: AZ::u64 m_id; }; @@ -51,10 +66,8 @@ namespace AzToolsFramework using RegisteredBoundId = IdType; static const RegisteredBoundId InvalidBoundId = RegisteredBoundId(0); - /** - * This class serves as the base class for the actual bound shapes that various DefaultContextBoundManager-derived - * classes return from the function CreateShape. - */ + //! This class serves as the base class for the actual bound shapes that various DefaultContextBoundManager-derived + //! classes return from the function CreateShape. class BoundShapeInterface { public: @@ -63,25 +76,33 @@ namespace AzToolsFramework explicit BoundShapeInterface(const RegisteredBoundId boundId) : m_boundId(boundId) , m_valid(false) - {} + { + } virtual ~BoundShapeInterface() = default; - RegisteredBoundId GetBoundId() const { return m_boundId; } + RegisteredBoundId GetBoundId() const + { + return m_boundId; + } - /** - * @param rayOrigin The origin of the ray to test with. - * @param rayDir The direction of the ray to test with. - * @param[out] rayIntersectionDistance The distance of the intersecting point closest to the ray origin. - * @return Boolean indicating whether there is a least one intersecting point between this bound shape and the ray. - */ - virtual bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) = 0; + //! @param rayOrigin The origin of the ray to test with. + //! @param rayDir The direction of the ray to test with. + //! @param[out] rayIntersectionDistance The distance of the intersecting point closest to the ray origin. + //! @return Boolean indicating whether there is a least one intersecting point between this bound shape and the ray. + virtual bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) = 0; virtual void SetShapeData(const BoundRequestShapeBase& shapeData) = 0; - void SetValidity(bool valid) { m_valid = valid; } - bool IsValid() const { return m_valid; } + void SetValidity(bool valid) + { + m_valid = valid; + } + + bool IsValid() const + { + return m_valid; + } private: RegisteredBoundId m_boundId; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/ContextBoundAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/ContextBoundAPI.h index 4a053ea758..7127ac82ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/ContextBoundAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/ContextBoundAPI.h @@ -1,22 +1,22 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once #include -#include #include #include #include +#include #include #include #include @@ -27,9 +27,7 @@ namespace AzToolsFramework { namespace Picking { - /** - * An interface concrete shape types can implement to create specific BoundShapeInterfaces. - */ + //! An interface concrete shape types can implement to create specific BoundShapeInterfaces. class BoundRequestShapeBase { public: @@ -114,11 +112,9 @@ namespace AzToolsFramework float m_radius; }; - /** - * The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4 - * in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and - * \ref corner_2 cannot be diagonal corners. - */ + //! The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4 + //! in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and + //! \ref corner_2 cannot be diagonal corners. class BoundShapeQuad : public BoundRequestShapeBase { public: @@ -138,9 +134,7 @@ namespace AzToolsFramework AZ::Vector3 m_corner4; }; - /** - * The line segment consists of two points in 3D space defining a line the user can interact with. - */ + //! The line segment consists of two points in 3D space defining a line the user can interact with. class BoundShapeLineSegment : public BoundRequestShapeBase { public: @@ -159,10 +153,8 @@ namespace AzToolsFramework float m_width; }; - /** - * The torus shape is approximated by a cylinder whose radius is the sum of the torus's major radius - * and minor radius and height is twice the torus's minor radius. - */ + //! The torus shape is approximated by a cylinder whose radius is the sum of the torus's major radius + //! and minor radius and height is twice the torus's minor radius. class BoundShapeTorus : public BoundRequestShapeBase { public: @@ -182,10 +174,8 @@ namespace AzToolsFramework float m_minorRadius; }; - /** - * The spline is specified by a number of vertices. A piecewise approximation of the curve - * is computed by using a number of linear steps (defined by the granularity of the curve). - */ + //! The spline is specified by a number of vertices. A piecewise approximation of the curve + //! is computed by using a number of linear steps (defined by the granularity of the curve). class BoundShapeSpline : public BoundRequestShapeBase { public: @@ -204,16 +194,14 @@ namespace AzToolsFramework float m_width; }; - /** - * Ray query for intersection against bounds. - */ + //! Ray query for intersection against bounds. struct RaySelectInfo { - AZ::Vector3 m_origin; ///< Start of ray. - AZ::Vector3 m_direction; ///< Direction of ray - make sure m_direction is unit length. - AZStd::vector> m_boundIdsHit; ///< Store the id of the intersected bound - ///< and the parameter of the corresponding - ///< intersecting point. + AZ::Vector3 m_origin; //!< Start of ray. + AZ::Vector3 m_direction; //!< Direction of ray - make sure m_direction is unit length. + AZStd::vector> m_boundIdsHit; //!< Store the id of the intersected bound + //!< and the parameter of the corresponding + //!< intersecting point. }; } // namespace Picking } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.cpp index d838413a67..342dc4b99e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ManipulatorBoundManager.h" @@ -16,8 +16,7 @@ namespace AzToolsFramework { namespace Picking { - RegisteredBoundId ManipulatorBoundManager::UpdateOrRegisterBound( - const BoundRequestShapeBase& shapeData, RegisteredBoundId boundId) + RegisteredBoundId ManipulatorBoundManager::UpdateOrRegisterBound(const BoundRequestShapeBase& shapeData, RegisteredBoundId boundId) { if (boundId == InvalidBoundId) { @@ -25,8 +24,7 @@ namespace AzToolsFramework boundId = m_nextBoundId++; } - if (auto result = m_boundIdToShapeMap.find(boundId); - result == m_boundIdToShapeMap.end()) + if (auto result = m_boundIdToShapeMap.find(boundId); result == m_boundIdToShapeMap.end()) { if (AZStd::shared_ptr createdShape = CreateShape(shapeData, boundId)) { @@ -49,19 +47,16 @@ namespace AzToolsFramework void ManipulatorBoundManager::UnregisterBound(const RegisteredBoundId boundId) { - if (const auto findIter = m_boundIdToShapeMap.find(boundId); - findIter != m_boundIdToShapeMap.end()) + if (const auto findIter = m_boundIdToShapeMap.find(boundId); findIter != m_boundIdToShapeMap.end()) { DeleteShape(findIter->second.get()); m_boundIdToShapeMap.erase(findIter); } } - void ManipulatorBoundManager::SetBoundValidity( - const RegisteredBoundId boundId, const bool valid) + void ManipulatorBoundManager::SetBoundValidity(const RegisteredBoundId boundId, const bool valid) { - if (auto found = m_boundIdToShapeMap.find(boundId); - found != m_boundIdToShapeMap.end()) + if (auto found = m_boundIdToShapeMap.find(boundId); found != m_boundIdToShapeMap.end()) { found->second->SetValidity(valid); } @@ -104,9 +99,9 @@ namespace AzToolsFramework const auto hitItr = AZStd::lower_bound( rayHits.begin(), rayHits.end(), BoundIdHitDistance(0, t), [](const BoundIdHitDistance& lhs, const BoundIdHitDistance& rhs) - { - return lhs.second < rhs.second; - }); + { + return lhs.second < rhs.second; + }); rayHits.insert(hitItr, AZStd::make_pair(bound->GetBoundId(), t)); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.h index 78e714c256..504f06bb49 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBoundManager.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -21,10 +21,8 @@ namespace AzToolsFramework { class BoundShapeInterface; - /** - * Handle creating, destroying and storing all active manipulator - * bounds for performing raycasts/picking against. - */ + //! Handle creating, destroying and storing all active manipulator + //! bounds for performing raycasts/picking against. class ManipulatorBoundManager { public: @@ -35,21 +33,19 @@ namespace AzToolsFramework ManipulatorBoundManager& operator=(const ManipulatorBoundManager&) = delete; ~ManipulatorBoundManager() = default; - RegisteredBoundId UpdateOrRegisterBound( - const BoundRequestShapeBase& shapeData, RegisteredBoundId id); + RegisteredBoundId UpdateOrRegisterBound(const BoundRequestShapeBase& shapeData, RegisteredBoundId id); void UnregisterBound(RegisteredBoundId boundId); void SetBoundValidity(RegisteredBoundId boundId, bool valid); - void RaySelect(RaySelectInfo &rayInfo); + void RaySelect(RaySelectInfo& rayInfo); private: - AZStd::shared_ptr CreateShape( - const BoundRequestShapeBase& ptrShape, RegisteredBoundId id); + AZStd::shared_ptr CreateShape(const BoundRequestShapeBase& ptrShape, RegisteredBoundId id); void DeleteShape(const BoundShapeInterface* boundShape); AZStd::unordered_map> m_boundIdToShapeMap; - AZStd::vector> m_bounds; ///< All current manipulator bounds. + AZStd::vector> m_bounds; //!< All current manipulator bounds. - RegisteredBoundId m_nextBoundId = RegisteredBoundId(1); ///< Next bound id to use when a bound is registered. + RegisteredBoundId m_nextBoundId = RegisteredBoundId(1); //!< Next bound id to use when a bound is registered. }; } // namespace Picking } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp index 8a9ebbacbc..8dca45cc9a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.cpp @@ -1,17 +1,18 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include #include +#include #include #include @@ -23,8 +24,7 @@ namespace AzToolsFramework const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance) { float vecRayIntersectionDistance; - if (AZ::Intersect::IntersectRaySphere( - rayOrigin, rayDirection, m_center, m_radius, vecRayIntersectionDistance) > 0) + if (AZ::Intersect::IntersectRaySphere(rayOrigin, rayDirection, m_center, m_radius, vecRayIntersectionDistance) > 0) { rayIntersectionDistance = vecRayIntersectionDistance; return true; @@ -45,8 +45,9 @@ namespace AzToolsFramework bool ManipulatorBoundBox::IntersectRay( const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance) { - return AZ::Intersect::IntersectRayBox(rayOrigin, rayDirection, m_center, m_axis1, m_axis2, m_axis3, - m_halfExtents.GetX(), m_halfExtents.GetY(), m_halfExtents.GetZ(), rayIntersectionDistance) > 0; + return AZ::Intersect::IntersectRayBox( + rayOrigin, rayDirection, m_center, m_axis1, m_axis2, m_axis3, m_halfExtents.GetX(), m_halfExtents.GetY(), + m_halfExtents.GetZ(), rayIntersectionDistance) > 0; } void ManipulatorBoundBox::SetShapeData(const BoundRequestShapeBase& shapeData) @@ -66,8 +67,7 @@ namespace AzToolsFramework { float t1 = std::numeric_limits::max(); float t2 = std::numeric_limits::max(); - if (AZ::Intersect::IntersectRayCappedCylinder( - rayOrigin, rayDirection, m_base, m_axis, m_height, m_radius, t1, t2) > 0) + if (AZ::Intersect::IntersectRayCappedCylinder(rayOrigin, rayDirection, m_base, m_axis, m_height, m_radius, t1, t2) > 0) { rayIntersectionDistance = AZStd::GetMin(t1, t2); return true; @@ -92,8 +92,7 @@ namespace AzToolsFramework { float t1 = std::numeric_limits::max(); float t2 = std::numeric_limits::max(); - if (AZ::Intersect::IntersectRayCone( - rayOrigin, rayDirection, m_apexPosition, m_dir, m_height, m_radius, t1, t2) > 0) + if (AZ::Intersect::IntersectRayCone(rayOrigin, rayDirection, m_apexPosition, m_dir, m_height, m_radius, t1, t2) > 0) { rayIntersectionDistance = AZStd::GetMin(t1, t2); return true; @@ -117,7 +116,7 @@ namespace AzToolsFramework const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance) { return AZ::Intersect::IntersectRayQuad( - rayOrigin, rayDirection, m_corner1, m_corner2, m_corner3, m_corner4, rayIntersectionDistance) > 0; + rayOrigin, rayDirection, m_corner1, m_corner2, m_corner3, m_corner4, rayIntersectionDistance) > 0; } void ManipulatorBoundQuad::SetShapeData(const BoundRequestShapeBase& shapeData) @@ -157,8 +156,7 @@ namespace AzToolsFramework float rayProportion, lineSegmentProportion; // note: here out param is proportion/percentage of line AZ::Intersect::ClosestSegmentSegment( - rayOrigin, rayOrigin + rayDirection * rayLength, - m_worldStart, m_worldEnd, rayProportion, lineSegmentProportion, + rayOrigin, rayOrigin + rayDirection * rayLength, m_worldStart, m_worldEnd, rayProportion, lineSegmentProportion, closestPosRay, closestPosLineSegment); float distanceFromLine = (closestPosRay - closestPosLineSegment).GetLength(); @@ -188,8 +186,7 @@ namespace AzToolsFramework { if (const AZStd::shared_ptr spline = m_spline.lock()) { - AZ::RaySplineQueryResult splineQueryResult = - AZ::IntersectSpline(m_transform, rayOrigin, rayDirection, *spline); + AZ::RaySplineQueryResult splineQueryResult = AZ::IntersectSpline(m_transform, rayOrigin, rayDirection, *spline); if (splineQueryResult.m_distanceSq <= m_width * m_width) { @@ -214,22 +211,25 @@ namespace AzToolsFramework } bool IntersectHollowCylinder( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, - const AZ::Vector3& center, const AZ::Vector3& axis, - const float minorRadius, const float majorRadius, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZ::Vector3& center, + const AZ::Vector3& axis, + const float minorRadius, + const float majorRadius, float& rayIntersectionDistance) { - float t1 = std::numeric_limits::max(); - float t2 = std::numeric_limits::max(); + float t1 = AZStd::numeric_limits::max(); + float t2 = AZStd::numeric_limits::max(); const AZ::Vector3 base = center - axis * minorRadius; if (AZ::Intersect::IntersectRayCappedCylinder( - rayOrigin, rayDirection, base, axis, minorRadius * 2.0f, majorRadius + minorRadius, t1, t2) > 0) + rayOrigin, rayDirection, base, axis, minorRadius * 2.0f, majorRadius + minorRadius, t1, t2) > 0) { - const float thresholdSq = powf(majorRadius - minorRadius, 2.0f); + const float threshold = majorRadius - minorRadius; + const float thresholdSq = threshold * threshold; // util lambda used for distance checks at both 't' values - const auto validHolowCylinderHit = - [&rayOrigin, &rayDirection, ¢er, thresholdSq](const float t) + const auto validHolowCylinderHit = [&rayOrigin, &rayDirection, ¢er, thresholdSq](const float t) { // only return a valid intersection if the hit was // not in the 'hollow' part of the cylinder diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h index ca9eeded11..d72e11fd0a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -27,36 +27,36 @@ namespace AzToolsFramework { namespace Picking { - class ManipulatorBoundSphere - : public BoundShapeInterface + class ManipulatorBoundSphere : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundSphere, "{64D1B863-F574-4B31-A4F2-C9744D8567B3}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundSphere, AZ::SystemAllocator, 0); explicit ManipulatorBoundSphere(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZ::Vector3 m_center = AZ::Vector3::CreateZero(); float m_radius = 0.0f; }; - class ManipulatorBoundBox - : public BoundShapeInterface + class ManipulatorBoundBox : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundBox, "{3AD46067-933F-49B4-82E1-DBF12C7BC02E}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundBox, AZ::SystemAllocator, 0); explicit ManipulatorBoundBox(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZ::Vector3 m_center = AZ::Vector3::CreateZero(); @@ -66,38 +66,38 @@ namespace AzToolsFramework AZ::Vector3 m_halfExtents = AZ::Vector3::CreateZero(); }; - class ManipulatorBoundCylinder - : public BoundShapeInterface + class ManipulatorBoundCylinder : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundCylinder, "{D248F9E4-22E6-41A8-898D-704DF307B533}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundCylinder, AZ::SystemAllocator, 0); explicit ManipulatorBoundCylinder(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; - AZ::Vector3 m_base = AZ::Vector3::CreateZero(); ///< The center of the circle at the base of the cylinder. + AZ::Vector3 m_base = AZ::Vector3::CreateZero(); //!< The center of the circle at the base of the cylinder. AZ::Vector3 m_axis = AZ::Vector3::CreateZero(); float m_height = 0.0f; float m_radius = 0.0f; }; - class ManipulatorBoundCone - : public BoundShapeInterface + class ManipulatorBoundCone : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundCone, "{9430440D-DFF2-4A60-9073-507C4E9DD65D}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundCone, AZ::SystemAllocator, 0); explicit ManipulatorBoundCone(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZ::Vector3 m_apexPosition = AZ::Vector3::CreateZero(); @@ -106,23 +106,21 @@ namespace AzToolsFramework float m_height = 0.0f; }; - /** - * The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4 - * in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and - * \ref corner_2 cannot be diagonal corners. - */ - class ManipulatorBoundQuad - : public BoundShapeInterface + //! The quad shape consists of 4 points in 3D space. Please set them from \ref m_corner1 to \ref m_corner4 + //! in either clock-wise winding or counter clock-wise winding. In another word, \ref m_corner1 and + //! \ref corner_2 cannot be diagonal corners. + class ManipulatorBoundQuad : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundQuad, "{3CDED61C-5786-4299-B5F2-5970DE4457AD}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundQuad, AZ::SystemAllocator, 0); explicit ManipulatorBoundQuad(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZ::Vector3 m_corner1 = AZ::Vector3::CreateZero(); @@ -131,18 +129,18 @@ namespace AzToolsFramework AZ::Vector3 m_corner4 = AZ::Vector3::CreateZero(); }; - class ManipulatorBoundTorus - : public BoundShapeInterface + class ManipulatorBoundTorus : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundTorus, "{46E4711C-178A-4F97-BC14-A048D096E7A1}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundTorus, AZ::SystemAllocator, 0); explicit ManipulatorBoundTorus(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; // Approximate a torus as a thin cylinder. A ray intersects a torus when the ray and the torus' @@ -150,22 +148,22 @@ namespace AzToolsFramework // center of the torus. AZ::Vector3 m_center = AZ::Vector3::CreateZero(); AZ::Vector3 m_axis = AZ::Vector3::CreateZero(); - float m_majorRadius = 0.0f; ///< Usually denoted as "R", the distance from the center of the tube to the center of the torus. - float m_minorRadius = 0.0f; ///< Usually denoted as "r", the radius of the tube. + float m_majorRadius = 0.0f; //!< Usually denoted as "R", the distance from the center of the tube to the center of the torus. + float m_minorRadius = 0.0f; //!< Usually denoted as "r", the radius of the tube. }; - class ManipulatorBoundLineSegment - : public BoundShapeInterface + class ManipulatorBoundLineSegment : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundLineSegment, "{66801554-1C1A-4E79-B1E7-342DFA779D53}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundLineSegment, AZ::SystemAllocator, 0); explicit ManipulatorBoundLineSegment(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZ::Vector3 m_worldStart = AZ::Vector3::CreateZero(); @@ -173,18 +171,18 @@ namespace AzToolsFramework float m_width = 0.0f; }; - class ManipulatorBoundSpline - : public BoundShapeInterface + class ManipulatorBoundSpline : public BoundShapeInterface { public: AZ_RTTI(ManipulatorBoundSpline, "{777760FF-8547-45AD-876F-16BA4D9D0584}", BoundShapeInterface); AZ_CLASS_ALLOCATOR(ManipulatorBoundSpline, AZ::SystemAllocator, 0); explicit ManipulatorBoundSpline(RegisteredBoundId boundId) - : BoundShapeInterface(boundId) {} + : BoundShapeInterface(boundId) + { + } - bool IntersectRay( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; + bool IntersectRay(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDir, float& rayIntersectionDistance) override; void SetShapeData(const BoundRequestShapeBase& shapeData) override; AZStd::weak_ptr m_spline; @@ -192,11 +190,14 @@ namespace AzToolsFramework float m_width = 0.0f; }; - /// Approximate intersection with a torus-like shape. + //! Approximate intersection with a torus-like shape. bool IntersectHollowCylinder( - const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, - const AZ::Vector3& center, const AZ::Vector3& axis, - float minorRadius, float majorRadius, + const AZ::Vector3& rayOrigin, + const AZ::Vector3& rayDirection, + const AZ::Vector3& center, + const AZ::Vector3& axis, + float minorRadius, + float majorRadius, float& rayIntersectionDistance); } // namespace Picking diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp index 7fa9724d65..8ed488b010 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorContextMenu.h" @@ -16,8 +16,7 @@ namespace AzToolsFramework { - void EditorContextMenuUpdate( - EditorContextMenu& contextMenu, const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + void EditorContextMenuUpdate(EditorContextMenu& contextMenu, const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -26,18 +25,17 @@ namespace AzToolsFramework mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down) { contextMenu.m_shouldOpen = true; - contextMenu.m_clickPoint = ViewportInteraction::QPointFromScreenPoint( - mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); + contextMenu.m_clickPoint = + ViewportInteraction::QPointFromScreenPoint(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); } // disable shouldOpen if right clicking an moving the mouse if (mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Move) { - const QPoint currentScreenCoords = ViewportInteraction::QPointFromScreenPoint( - mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); + const QPoint currentScreenCoords = + ViewportInteraction::QPointFromScreenPoint(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates); - contextMenu.m_shouldOpen = contextMenu.m_shouldOpen && - (currentScreenCoords - contextMenu.m_clickPoint).manhattanLength() < 2; + contextMenu.m_shouldOpen = contextMenu.m_shouldOpen && (currentScreenCoords - contextMenu.m_clickPoint).manhattanLength() < 2; } // do show the context menu @@ -58,9 +56,8 @@ namespace AzToolsFramework // Populate global context menu. const int contextMenuFlag = 0; EditorEvents::Bus::BroadcastReverse( - &EditorEvents::PopulateEditorGlobalContextMenu, - contextMenu.m_menu.data(), AzFramework::Vector2FromScreenPoint( - mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates), + &EditorEvents::PopulateEditorGlobalContextMenu, contextMenu.m_menu.data(), + AzFramework::Vector2FromScreenPoint(mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates), contextMenuFlag); if (!contextMenu.m_menu->isEmpty()) @@ -70,4 +67,4 @@ namespace AzToolsFramework } } } -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.h index ebce02fa4c..ff5bffc544 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.h @@ -1,22 +1,22 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once #include +#include #include #include -#include namespace AzToolsFramework { @@ -25,7 +25,7 @@ namespace AzToolsFramework struct MouseInteractionEvent; } - /// State of when and where the right-click context menu should appear. + //! State of when and where the right-click context menu should appear. struct EditorContextMenu final { bool m_shouldOpen = false; @@ -33,8 +33,6 @@ namespace AzToolsFramework QPointer m_menu; }; - /// Update to run for context menu (when should it appear/disappear etc). - void EditorContextMenuUpdate( - EditorContextMenu& contextMenu, - const ViewportInteraction::MouseInteractionEvent& mouseInteraction); + //! Update to run for context menu (when should it appear/disappear etc). + void EditorContextMenuUpdate(EditorContextMenu& contextMenu, const ViewportInteraction::MouseInteractionEvent& mouseInteraction); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.cpp index cd9382c497..10016fbb13 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "VertexContainerDisplay.h" @@ -23,8 +23,7 @@ namespace AzToolsFramework const AZ::Vector3 DefaultVertexTextOffset = AZ::Vector3(0.0f, 0.0f, -0.1f); void DisplayVertexContainerIndex( - AzFramework::DebugDisplayRequests& debugDisplay, - const AZ::Vector3& position, const size_t index, const float textSize) + AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const size_t index, const float textSize) { AZStd::string indexFormat = AZStd::string::format("[%zu]", index); debugDisplay.DrawTextLabel(position, textSize, indexFormat.c_str(), true); @@ -36,7 +35,8 @@ namespace AzToolsFramework const AZ::FixedVertices& vertices, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, - const bool selected, const float textSize, + const bool selected, + const float textSize, const AZ::Color& textColor, const AZ::Vector3& textOffset) { @@ -52,11 +52,12 @@ namespace AzToolsFramework if (vertices.GetVertex(vertIndex, vertex)) { DisplayVertexContainerIndex( - debugDisplay, transform.TransformPoint(nonUniformScale * (AdaptVertexOut(vertex) + textOffset)), vertIndex, textSize); + debugDisplay, transform.TransformPoint(nonUniformScale * (AdaptVertexOut(vertex) + textOffset)), vertIndex, + textSize); } } } - } + } // namespace VertexContainerDisplay // explicit template instantiations template void VertexContainerDisplay::DisplayVertexContainerIndices( @@ -64,7 +65,8 @@ namespace AzToolsFramework const AZ::FixedVertices& vertices, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, - bool selected, float textSize, + bool selected, + float textSize, const AZ::Color& textColor, const AZ::Vector3& textOffset); template void VertexContainerDisplay::DisplayVertexContainerIndices( @@ -72,7 +74,8 @@ namespace AzToolsFramework const AZ::FixedVertices& vertices, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, - bool selected, float textSize, + bool selected, + float textSize, const AZ::Color& textColor, const AZ::Vector3& textOffset); -} +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.h index 1717d770df..c734740d3c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/VertexContainerDisplay.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,22 +22,23 @@ namespace AzFramework namespace AzToolsFramework { - /// Utility functions for rendering vertex container indices. + //! Utility functions for rendering vertex container indices. namespace VertexContainerDisplay { extern const float DefaultVertexTextSize; extern const AZ::Color DefaultVertexTextColor; extern const AZ::Vector3 DefaultVertexTextOffset; - /// Displays all vertex container indices as text at the position of each vertex when selected + //! Displays all vertex container indices as text at the position of each vertex when selected template void DisplayVertexContainerIndices( AzFramework::DebugDisplayRequests& debugDisplay, const AZ::FixedVertices& vertices, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, - bool selected, float textSize = DefaultVertexTextSize, + bool selected, + float textSize = DefaultVertexTextSize, const AZ::Color& textColor = DefaultVertexTextColor, const AZ::Vector3& textOffset = DefaultVertexTextOffset); - } + } // namespace VertexContainerDisplay } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 91eee18cb7..85250f2a32 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #include @@ -31,45 +31,51 @@ namespace AzToolsFramework { namespace ViewportInteraction { - /// Result of handling mouse interaction. + //! Result of handling mouse interaction. enum class MouseInteractionResult { - Manipulator, ///< The manipulator manager handled the interaction. - Viewport, ///< The viewport handled the interaction. - None ///< The interaction was not handled. + Manipulator, //!< The manipulator manager handled the interaction. + Viewport, //!< The viewport handled the interaction. + None //!< The interaction was not handled. }; - /// Interface for handling mouse viewport events. + //! Interface for handling mouse viewport events. class MouseViewportRequests { public: - /// @cond + //! @cond virtual ~MouseViewportRequests() = default; - /// @endcond + //! @endcond - /// Implement this function to handle a particular mouse event. - virtual bool HandleMouseInteraction( - const MouseInteractionEvent& /*mouseInteraction*/) { return false; } + //! Implement this function to handle a particular mouse event. + virtual bool HandleMouseInteraction(const MouseInteractionEvent& /*mouseInteraction*/) + { + return false; + } }; - - /// Interface for internal handling mouse viewport events. + + //! Interface for internal handling mouse viewport events. class InternalMouseViewportRequests { public: - /// @cond + //! @cond virtual ~InternalMouseViewportRequests() = default; - /// @endcond + //! @endcond - /// Implement this function to have the viewport handle this mouse event. - virtual bool InternalHandleMouseViewportInteraction( - const MouseInteractionEvent& /*mouseInteraction*/) { return false; } + //! Implement this function to have the viewport handle this mouse event. + virtual bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& /*mouseInteraction*/) + { + return false; + } - /// Implement this function to have manipulators handle this mouse event. - virtual bool InternalHandleMouseManipulatorInteraction( - const MouseInteractionEvent& /*mouseInteraction*/) { return false; } + //! Implement this function to have manipulators handle this mouse event. + virtual bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& /*mouseInteraction*/) + { + return false; + } - /// Helper to call both viewport and manipulator handle mouse events - /// @note Manipulators always attempt to intercept the event first. + //! Helper to call both viewport and manipulator handle mouse events + //! @note Manipulators always attempt to intercept the event first. MouseInteractionResult InternalHandleAllMouseInteractions(const MouseInteractionEvent& mouseInteraction); }; @@ -90,117 +96,118 @@ namespace AzToolsFramework } } - /// Interface for viewport selection behaviors. + //! Interface for viewport selection behaviors. class ViewportDisplayNotifications { public: - /// @cond + //! @cond virtual ~ViewportDisplayNotifications() = default; - /// @endcond + //! @endcond - /// Display drawing in world space. - /// \ref DisplayViewportSelection is called from \ref EditorInteractionSystemComponent::DisplayViewport. - /// DisplayViewport exists on the \ref AzFramework::ViewportDebugDisplayEventBus and is called from \ref CRenderViewport. - /// \ref DisplayViewportSelection is called after \ref CalculateVisibleEntityDatas on the \ref EditorVisibleEntityDataCache, - /// this ensures usage of the entity cache will be up to date (do not implement \ref AzFramework::ViewportDebugDisplayEventBus - /// directly if wishing to use the \ref EditorVisibleEntityDataCache). + //! Display drawing in world space. + //! \ref DisplayViewportSelection is called from \ref EditorInteractionSystemComponent::DisplayViewport. + //! DisplayViewport exists on the \ref AzFramework::ViewportDebugDisplayEventBus and is called from \ref CRenderViewport. + //! \ref DisplayViewportSelection is called after \ref CalculateVisibleEntityDatas on the \ref EditorVisibleEntityDataCache, + //! this ensures usage of the entity cache will be up to date (do not implement \ref AzFramework::ViewportDebugDisplayEventBus + //! directly if wishing to use the \ref EditorVisibleEntityDataCache). virtual void DisplayViewportSelection( - const AzFramework::ViewportInfo& /*viewportInfo*/, - AzFramework::DebugDisplayRequests& /*debugDisplay*/) {} - /// Display drawing in screen space. - /// \ref DisplayViewportSelection2d is called after \ref DisplayViewportSelection when the viewport has been - /// configured to be orthographic in \ref CRenderViewport. All screen space drawing can be performed here. + const AzFramework::ViewportInfo& /*viewportInfo*/, AzFramework::DebugDisplayRequests& /*debugDisplay*/) + { + } + //! Display drawing in screen space. + //! \ref DisplayViewportSelection2d is called after \ref DisplayViewportSelection when the viewport has been + //! configured to be orthographic in \ref CRenderViewport. All screen space drawing can be performed here. virtual void DisplayViewportSelection2d( - const AzFramework::ViewportInfo& /*viewportInfo*/, - AzFramework::DebugDisplayRequests& /*debugDisplay*/) {} + const AzFramework::ViewportInfo& /*viewportInfo*/, AzFramework::DebugDisplayRequests& /*debugDisplay*/) + { + } }; - /// Interface for internal handling mouse viewport events and display notifications. - /// Implement this for types wishing to provide viewport functionality and - /// set it by using \ref EditorInteractionSystemViewportSelectionRequestBus. + //! Interface for internal handling mouse viewport events and display notifications. + //! Implement this for types wishing to provide viewport functionality and + //! set it by using \ref EditorInteractionSystemViewportSelectionRequestBus. class InternalViewportSelectionRequests : public ViewportDisplayNotifications , public InternalMouseViewportRequests { }; - /// Interface for handling mouse viewport events and display notifications. - /// Use this interface for composition types used by InternalViewportSelectionRequests. + //! Interface for handling mouse viewport events and display notifications. + //! Use this interface for composition types used by InternalViewportSelectionRequests. class ViewportSelectionRequests : public ViewportDisplayNotifications , public MouseViewportRequests { }; - /// The EBusTraits for ViewportInteractionRequests. - class ViewportEBusTraits - : public AZ::EBusTraits + //! The EBusTraits for ViewportInteractionRequests. + class ViewportEBusTraits : public AZ::EBusTraits { public: - using BusIdType = AzFramework::ViewportId; ///< ViewportId - used to address requests to this EBus. + using BusIdType = AzFramework::ViewportId; //!< ViewportId - used to address requests to this EBus. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; }; - /// A ray projection, originating from a point and extending in a direction specified as a normal. + //! A ray projection, originating from a point and extending in a direction specified as a normal. struct ProjectedViewportRay { AZ::Vector3 origin; AZ::Vector3 direction; }; - /// Requests that can be made to the viewport to query and modify its state. + //! Requests that can be made to the viewport to query and modify its state. class ViewportInteractionRequests { public: - /// Return the current camera state for this viewport. + //! Return the current camera state for this viewport. virtual AzFramework::CameraState GetCameraState() = 0; - /// Return if grid snapping is enabled. + //! Return if grid snapping is enabled. virtual bool GridSnappingEnabled() = 0; - /// Return the grid snapping size. + //! Return the grid snapping size. virtual float GridSize() = 0; - /// Does the grid currently want to be displayed. + //! Does the grid currently want to be displayed. virtual bool ShowGrid() = 0; - /// Return if angle snapping is enabled. + //! Return if angle snapping is enabled. virtual bool AngleSnappingEnabled() = 0; - /// Return the angle snapping/step size. + //! Return the angle snapping/step size. virtual float AngleStep() = 0; - /// Transform a point in world space to screen space coordinates in Qt Widget space. - /// Multiply by DeviceScalingFactor to get the position in viewport pixel space. + //! Transform a point in world space to screen space coordinates in Qt Widget space. + //! Multiply by DeviceScalingFactor to get the position in viewport pixel space. virtual AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) = 0; - /// Transform a point from Qt widget screen space to world space based on the given clip space depth. - /// Depth specifies a relative camera depth to project in the range of [0.f, 1.f]. - /// Returns the world space position if successful. + //! Transform a point from Qt widget screen space to world space based on the given clip space depth. + //! Depth specifies a relative camera depth to project in the range of [0.f, 1.f]. + //! Returns the world space position if successful. virtual AZStd::optional ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) = 0; - /// Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane. - /// Returns a ray containing the ray's origin and a direction normal, if successful. + //! Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane. + //! Returns a ray containing the ray's origin and a direction normal, if successful. virtual AZStd::optional ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0; - /// Gets the DPI scaling factor that translates Qt widget space into viewport pixel space. + //! Gets the DPI scaling factor that translates Qt widget space into viewport pixel space. virtual float DeviceScalingFactor() = 0; protected: ~ViewportInteractionRequests() = default; }; - /// Interface to return only viewport specific settings (e.g. snapping). + //! Interface to return only viewport specific settings (e.g. snapping). class ViewportSettings { public: virtual ~ViewportSettings() = default; - /// Return if grid snapping is enabled. + //! Return if grid snapping is enabled. virtual bool GridSnappingEnabled() const = 0; - /// Return the grid snapping size. + //! Return the grid snapping size. virtual float GridSize() const = 0; - /// Does the grid currently want to be displayed. + //! Does the grid currently want to be displayed. virtual bool ShowGrid() const = 0; - /// Return if angle snapping is enabled. + //! Return if angle snapping is enabled. virtual bool AngleSnappingEnabled() const = 0; - /// Return the angle snapping/step size. + //! Return the angle snapping/step size. virtual float AngleStep() const = 0; }; - /// Type to inherit to implement ViewportInteractionRequests. + //! Type to inherit to implement ViewportInteractionRequests. using ViewportInteractionRequestBus = AZ::EBus; //! Requests to freeze the Viewport Input @@ -221,62 +228,62 @@ namespace AzToolsFramework //! Type to inherit to implement ViewportFreezeRequests. using ViewportFreezeRequestBus = AZ::EBus; - /// Viewport requests that are only guaranteed to be serviced by the Main Editor viewport. + //! Viewport requests that are only guaranteed to be serviced by the Main Editor viewport. class MainEditorViewportInteractionRequests { public: - /// Given a point in screen space, return the picked entity (if any). - /// Picked EntityId will be returned, InvalidEntityId will be returned on failure. + //! Given a point in screen space, return the picked entity (if any). + //! Picked EntityId will be returned, InvalidEntityId will be returned on failure. virtual AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) = 0; - /// Given a point in screen space, return the terrain position in world space. + //! Given a point in screen space, return the terrain position in world space. virtual AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) = 0; - /// Return the terrain height given a world position in 2d (xy plane). + //! Return the terrain height given a world position in 2d (xy plane). virtual float TerrainHeight(const AZ::Vector2& position) = 0; - /// Given the current view frustum (viewport) return all visible entities. + //! Given the current view frustum (viewport) return all visible entities. virtual void FindVisibleEntities(AZStd::vector& visibleEntities) = 0; - /// Is the user holding a modifier key to move the manipulator space from local to world. + //! Is the user holding a modifier key to move the manipulator space from local to world. virtual bool ShowingWorldSpace() = 0; - /// Return the widget to use as the parent for the viewport context menu. + //! Return the widget to use as the parent for the viewport context menu. virtual QWidget* GetWidgetForViewportContextMenu() = 0; - /// Set the render context for the viewport. + //! Set the render context for the viewport. virtual void BeginWidgetContext() = 0; - /// End the render context for the viewport. - /// Return to previous context before Begin was called. + //! End the render context for the viewport. + //! Return to previous context before Begin was called. virtual void EndWidgetContext() = 0; protected: ~MainEditorViewportInteractionRequests() = default; }; - /// Type to inherit to implement MainEditorViewportInteractionRequests. + //! Type to inherit to implement MainEditorViewportInteractionRequests. using MainEditorViewportInteractionRequestBus = AZ::EBus; - /// Viewport requests for managing the viewport's cursor state. + //! Viewport requests for managing the viewport's cursor state. class ViewportMouseCursorRequests { public: - /// Begins hiding the cursor and locking it in place, to prevent the cursor from escaping the viewport window. + //! Begins hiding the cursor and locking it in place, to prevent the cursor from escaping the viewport window. virtual void BeginCursorCapture() = 0; - /// Restores the cursor and ends locking it in place, allowing it to be moved freely. + //! 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. + //! Gets the most recent recorded cursor position in the viewport in screen space coordinates. virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0; - /// Gets the cursor position recorded prior to the most recent cursor position. - /// Note: The cursor may be captured by the viewport, in which case this may not correspond to the last result - /// from ViewportCursorScreenPosition. This method will always return the correct position to generate a mouse - /// position delta. + //! Gets the cursor position recorded prior to the most recent cursor position. + //! Note: The cursor may be captured by the viewport, in which case this may not correspond to the last result + //! from ViewportCursorScreenPosition. This method will always return the correct position to generate a mouse + //! position delta. virtual AZStd::optional PreviousViewportCursorScreenPosition() = 0; - /// Is mouse over viewport. + //! Is mouse over viewport. virtual bool IsMouseOver() const = 0; protected: ~ViewportMouseCursorRequests() = default; }; - /// Type to inherit to implement MainEditorViewportInteractionRequests. + //! Type to inherit to implement MainEditorViewportInteractionRequests. using ViewportMouseCursorRequestBus = AZ::EBus; - /// A helper to wrap Begin/EndWidgetContext. + //! A helper to wrap Begin/EndWidgetContext. class WidgetContextGuard { public: @@ -294,17 +301,16 @@ namespace AzToolsFramework } private: - int m_viewportId; ///< The viewport id the widget context is being set on. + int m_viewportId; //!< The viewport id the widget context is being set on. }; } // namespace ViewportInteraction - /// Utility function to return EntityContextId. + //! Utility function to return EntityContextId. inline AzFramework::EntityContextId GetEntityContextId() { AzFramework::EntityContextId entityContextId; - EditorEntityContextRequestBus::BroadcastResult( - entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); + EditorEntityContextRequestBus::BroadcastResult(entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId); return entityContextId; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp index 8d26054562..99808fcd56 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ViewportTypes.h" @@ -23,26 +23,24 @@ namespace AzToolsFramework { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class()-> - Field("KeyboardModifiers", &KeyboardModifiers::m_keyModifiers); + serializeContext->Class()->Field("KeyboardModifiers", &KeyboardModifiers::m_keyModifiers); - serializeContext->Class()-> - Field("MouseButtons", &MouseButtons::m_mouseButtons); + serializeContext->Class()->Field("MouseButtons", &MouseButtons::m_mouseButtons); - serializeContext->Class()-> - Field("CameraId", &InteractionId::m_cameraId)-> - Field("ViewportId", &InteractionId::m_viewportId); + serializeContext->Class() + ->Field("CameraId", &InteractionId::m_cameraId) + ->Field("ViewportId", &InteractionId::m_viewportId); - serializeContext->Class()-> - Field("RayOrigin", &MousePick::m_rayOrigin)-> - Field("RayDirection", &MousePick::m_rayDirection)-> - Field("ScreenCoordinates", &MousePick::m_screenCoordinates); + serializeContext->Class() + ->Field("RayOrigin", &MousePick::m_rayOrigin) + ->Field("RayDirection", &MousePick::m_rayDirection) + ->Field("ScreenCoordinates", &MousePick::m_screenCoordinates); - serializeContext->Class()-> - Field("MousePick", &MouseInteraction::m_mousePick)-> - Field("MouseButtons", &MouseInteraction::m_mouseButtons)-> - Field("InteractionId", &MouseInteraction::m_interactionId)-> - Field("KeyboardModifiers", &MouseInteraction::m_keyboardModifiers); + serializeContext->Class() + ->Field("MousePick", &MouseInteraction::m_mousePick) + ->Field("MouseButtons", &MouseInteraction::m_mouseButtons) + ->Field("InteractionId", &MouseInteraction::m_interactionId) + ->Field("KeyboardModifiers", &MouseInteraction::m_keyboardModifiers); MouseInteractionEvent::Reflect(*serializeContext); } @@ -50,10 +48,10 @@ namespace AzToolsFramework void MouseInteractionEvent::Reflect(AZ::SerializeContext& serializeContext) { - serializeContext.Class()-> - Field("MouseInteraction", &MouseInteractionEvent::m_mouseInteraction)-> - Field("MouseEvent", &MouseInteractionEvent::m_mouseEvent)-> - Field("WheelDelta", &MouseInteractionEvent::m_wheelDelta); + serializeContext.Class() + ->Field("MouseInteraction", &MouseInteractionEvent::m_mouseInteraction) + ->Field("MouseEvent", &MouseInteractionEvent::m_mouseEvent) + ->Field("WheelDelta", &MouseInteractionEvent::m_wheelDelta); } - } -} + } // namespace ViewportInteraction +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h index d59044e68f..ad045888bc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportTypes.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -27,57 +27,75 @@ namespace AZ namespace AzToolsFramework { - /// Viewport related types that are used when interacting with the viewport. + //! Viewport related types that are used when interacting with the viewport. namespace ViewportInteraction { - /// Flags to represent each modifier key. + //! Flags to represent each modifier key. enum class KeyboardModifier : AZ::u32 { - None = 0, ///< No keyboard modifier. - Alt = 0x01, ///< Alt keyboard modifier. - Shift = 0x02, ///< Shift keyboard modifier. - Ctrl = 0x04, ///< Ctrl keyboard modifier. - Control = Ctrl ///< Alias for Ctrl modifier. + None = 0, //!< No keyboard modifier. + Alt = 0x01, //!< Alt keyboard modifier. + Shift = 0x02, //!< Shift keyboard modifier. + Ctrl = 0x04, //!< Ctrl keyboard modifier. + Control = Ctrl //!< Alias for Ctrl modifier. }; - /// Flags to represent each mouse button. + //! Flags to represent each mouse button. enum class MouseButton : AZ::u32 { - None = 0, ///< No mouse buttons. - Left = 0x01, ///< Left mouse button. - Middle = 0x02, ///< Middle mouse button. - Right = 0x04 ///< Right mouse button. + None = 0, //!< No mouse buttons. + Left = 0x01, //!< Left mouse button. + Middle = 0x02, //!< Middle mouse button. + Right = 0x04 //!< Right mouse button. }; - /// The type of mouse event that occurred. + //! The type of mouse event that occurred. enum class MouseEvent { - Up, ///< Mouse up event, - Down, ///< Mouse down event. - DoubleClick, ///< Mouse double click event. - Wheel, ///< Mouse wheel event. - Move, ///< Mouse move event. + Up, //!< Mouse up event, + Down, //!< Mouse down event. + DoubleClick, //!< Mouse double click event. + Wheel, //!< Mouse wheel event. + Move, //!< Mouse move event. }; - /// Interface over keyboard modifier to query which key is pressed. + //! Interface over keyboard modifier to query which key is pressed. struct KeyboardModifiers { - /// @cond + //! @cond AZ_TYPE_INFO(KeyboardModifiers, "{2635F4DF-E7DC-4919-A97B-9AE35FE086D8}"); KeyboardModifiers() = default; - /// @endcond + //! @endcond - /// Explicit constructor to create a KeyboardModifier struct. - explicit KeyboardModifiers(const AZ::u32 keyModifiers) : m_keyModifiers(keyModifiers) {} + //! Explicit constructor to create a KeyboardModifier struct. + explicit KeyboardModifiers(const AZ::u32 keyModifiers) + : m_keyModifiers(keyModifiers) + { + } - /// Given the current keyboard modifiers, is the Alt key held. - bool Alt() const { return (m_keyModifiers & static_cast(KeyboardModifier::Alt)) != 0; } - /// Given the current keyboard modifiers, is the Shift key held. - bool Shift() const { return (m_keyModifiers & static_cast(KeyboardModifier::Shift)) != 0; } - /// Given the current keyboard modifiers, is the Ctrl key held. - bool Ctrl() const { return (m_keyModifiers & static_cast(KeyboardModifier::Ctrl)) != 0; } - /// Given the current keyboard modifiers, are none being held. - bool None() const { return m_keyModifiers == static_cast(KeyboardModifier::None); } + //! Given the current keyboard modifiers, is the Alt key held. + bool Alt() const + { + return (m_keyModifiers & static_cast(KeyboardModifier::Alt)) != 0; + } + + //! Given the current keyboard modifiers, is the Shift key held. + bool Shift() const + { + return (m_keyModifiers & static_cast(KeyboardModifier::Shift)) != 0; + } + + //! Given the current keyboard modifiers, is the Ctrl key held. + bool Ctrl() const + { + return (m_keyModifiers & static_cast(KeyboardModifier::Ctrl)) != 0; + } + + //! Given the current keyboard modifiers, are none being held. + bool None() const + { + return m_keyModifiers == static_cast(KeyboardModifier::None); + } bool operator==(const KeyboardModifiers& keyboardModifiers) const { @@ -89,132 +107,162 @@ namespace AzToolsFramework return m_keyModifiers != keyboardModifiers.m_keyModifiers; } - AZ::u32 m_keyModifiers = 0; ///< Raw keyboard modifier state. + AZ::u32 m_keyModifiers = 0; //!< Raw keyboard modifier state. }; - /// Interface over mouse buttons to query which button is pressed. + //! Interface over mouse buttons to query which button is pressed. struct MouseButtons { - /// @cond + //! @cond AZ_TYPE_INFO(MouseButtons, "{1D137B5D-73BF-4FD9-BECA-85E6DC3786CB}"); MouseButtons() = default; - /// @endcond + //! @endcond - /// Explicit constructor to create a MouseButton struct. - explicit MouseButtons(const AZ::u32 mouseButtons) : m_mouseButtons(mouseButtons) {} + //! Explicit constructor to create a MouseButton struct. + explicit MouseButtons(const AZ::u32 mouseButtons) + : m_mouseButtons(mouseButtons) + { + } - /// Given the current mouse state, is the left mouse button held. - bool Left() const { return (m_mouseButtons & static_cast(MouseButton::Left)) != 0; } - /// Given the current mouse state, is the middle mouse button held. - bool Middle() const { return (m_mouseButtons & static_cast(MouseButton::Middle)) != 0; } - /// Given the current mouse state, is the right mouse button held. - bool Right() const { return (m_mouseButtons & static_cast(MouseButton::Right)) != 0; } - /// Given the current mouse state, are no mouse buttons held. - bool None() const { return m_mouseButtons == static_cast(MouseButton::None); } - /// Given the current mouse state, are any mouse buttons held. - bool Any() const { return m_mouseButtons != static_cast(MouseButton::None); } + //! Given the current mouse state, is the left mouse button held. + bool Left() const + { + return (m_mouseButtons & static_cast(MouseButton::Left)) != 0; + } - AZ::u32 m_mouseButtons = 0; ///< Current mouse button state (flags). + //! Given the current mouse state, is the middle mouse button held. + bool Middle() const + { + return (m_mouseButtons & static_cast(MouseButton::Middle)) != 0; + } + + //! Given the current mouse state, is the right mouse button held. + bool Right() const + { + return (m_mouseButtons & static_cast(MouseButton::Right)) != 0; + } + + //! Given the current mouse state, are no mouse buttons held. + bool None() const + { + return m_mouseButtons == static_cast(MouseButton::None); + } + + //! Given the current mouse state, are any mouse buttons held. + bool Any() const + { + return m_mouseButtons != static_cast(MouseButton::None); + } + + AZ::u32 m_mouseButtons = 0; //!< Current mouse button state (flags). }; - /// Information relevant when interacting with a particular viewport. + //! Information relevant when interacting with a particular viewport. struct InteractionId { - /// @cond + //! @cond AZ_TYPE_INFO(InteractionId, "{35593FC2-846F-4AAD-8044-4CD84EC84F9A}"); InteractionId() = default; - /// @endcond + //! @endcond InteractionId(AZ::EntityId cameraId, int viewportId) - : m_cameraId(cameraId), m_viewportId(viewportId) {} + : m_cameraId(cameraId) + , m_viewportId(viewportId) + { + } - AZ::EntityId m_cameraId; ///< The entity id of the viewport camera. - int m_viewportId = 0; ///< The id of the viewport being interacted with. + AZ::EntityId m_cameraId; //!< The entity id of the viewport camera. + int m_viewportId = 0; //!< The id of the viewport being interacted with. }; - /// Data representing a mouse pick ray. + //! Data representing a mouse pick ray. struct MousePick { - /// @cond + //! @cond AZ_TYPE_INFO(MousePick, "{A69B9562-FC8C-4DE7-9137-0FF867B1513D}"); MousePick() = default; - /// @endcond + //! @endcond - AZ::Vector3 m_rayOrigin = AZ::Vector3::CreateZero(); ///< World space. - AZ::Vector3 m_rayDirection = AZ::Vector3::CreateZero(); ///< World space - normalized. - AzFramework::ScreenPoint m_screenCoordinates = {}; ///< Screen space. + AZ::Vector3 m_rayOrigin = AZ::Vector3::CreateZero(); //!< World space. + AZ::Vector3 m_rayDirection = AZ::Vector3::CreateZero(); //!< World space - normalized. + AzFramework::ScreenPoint m_screenCoordinates = {}; //!< Screen space. }; - /// State relating to an individual mouse interaction. + //! State relating to an individual mouse interaction. struct MouseInteraction { - /// @cond + //! @cond AZ_TYPE_INFO(MouseInteraction, "{E67357C3-DFE1-40DF-921F-9CBCFE63A68C}"); MouseInteraction() = default; - /// @endcond + //! @endcond - MousePick m_mousePick; ///< The mouse pick ray in world space and screen coordinates in screen space. - MouseButtons m_mouseButtons; ///< The current state of the mouse buttons. + MousePick m_mousePick; //!< The mouse pick ray in world space and screen coordinates in screen space. + MouseButtons m_mouseButtons; //!< The current state of the mouse buttons. InteractionId m_interactionId; /**< The EntityId of the camera this click came from - * and the id of the viewport it originated from. */ - KeyboardModifiers m_keyboardModifiers; ///< The state of the keyboard modifiers (Alt/Ctrl/Shift). + * and the id of the viewport it originated from. */ + KeyboardModifiers m_keyboardModifiers; //!< The state of the keyboard modifiers (Alt/Ctrl/Shift). }; - /// Structure to compose MouseInteraction (mouse state) and - /// MouseEvent (MouseEvent::MouseUp/MouseEvent::DownMove etc.) + //! Structure to compose MouseInteraction (mouse state) and + //! MouseEvent (MouseEvent::MouseUp/MouseEvent::DownMove etc.) struct MouseInteractionEvent { - /// @cond + //! @cond AZ_TYPE_INFO(MouseInteractionEvent, "{67FE0826-DD59-4B5B-BEFE-421E83EA7F31}"); MouseInteractionEvent() = default; - /// @endcond + //! @endcond static void Reflect(AZ::SerializeContext& context); - /// Constructor to create a default MouseInteractionEvent + //! Constructor to create a default MouseInteractionEvent MouseInteractionEvent(MouseInteraction mouseInteraction, const MouseEvent mouseEvent) : m_mouseInteraction(std::move(mouseInteraction)) - , m_mouseEvent(mouseEvent) {} + , m_mouseEvent(mouseEvent) + { + } - /// Special constructor for mouse wheel event. + //! Special constructor for mouse wheel event. MouseInteractionEvent(MouseInteraction mouseInteraction, const float wheelDelta) : m_mouseInteraction(std::move(mouseInteraction)) , m_mouseEvent(MouseEvent::Wheel) - , m_wheelDelta(wheelDelta) {} + , m_wheelDelta(wheelDelta) + { + } - MouseInteraction m_mouseInteraction; ///< Mouse state. - MouseEvent m_mouseEvent; ///< Mouse event. + MouseInteraction m_mouseInteraction; //!< Mouse state. + MouseEvent m_mouseEvent; //!< Mouse event. - /// Special friend function to return the mouse wheel delta (scroll amount) - /// if the event was of type MouseEvent::Wheel. + //! Special friend function to return the mouse wheel delta (scroll amount) + //! if the event was of type MouseEvent::Wheel. friend float MouseWheelDelta(const MouseInteractionEvent& mouseInteractionEvent); private: - float m_wheelDelta = 0.0f; ///< The amount the mouse wheel moved during a mouse wheel event. + float m_wheelDelta = 0.0f; //!< The amount the mouse wheel moved during a mouse wheel event. }; - /// Checked access to mouse wheel delta - ensure event originated from the mouse wheel. + //! Checked access to mouse wheel delta - ensure event originated from the mouse wheel. inline float MouseWheelDelta(const MouseInteractionEvent& mouseInteractionEvent) { - AZ_Assert(mouseInteractionEvent.m_mouseEvent == MouseEvent::Wheel, + AZ_Assert( + mouseInteractionEvent.m_mouseEvent == MouseEvent::Wheel, "Attempting to access mouse wheel delta when mouse interaction event was not mouse wheel"); return mouseInteractionEvent.m_wheelDelta; } - /// Return QPoint from AzFramework::ScreenPoint. + //! Return QPoint from AzFramework::ScreenPoint. inline QPoint QPointFromScreenPoint(const AzFramework::ScreenPoint& screenPoint) { - return {screenPoint.m_x, screenPoint.m_y}; + return { screenPoint.m_x, screenPoint.m_y }; } - /// Return AzFramework::ScreenPoint from QPoint. + //! Return AzFramework::ScreenPoint from QPoint. inline AzFramework::ScreenPoint ScreenPointFromQPoint(const QPoint& qpoint) { - return AzFramework::ScreenPoint{qpoint.x(), qpoint.y()}; + return AzFramework::ScreenPoint{ qpoint.x(), qpoint.y() }; } - /// Map from Qt -> Open 3D Engine buttons.>>>>>>> main + //! Map from Qt -> Open 3D Engine buttons.>>>>>>> main inline AZ::u32 TranslateMouseButtons(const Qt::MouseButtons buttons) { AZ::u32 result = 0; @@ -224,7 +272,7 @@ namespace AzToolsFramework return result; } - /// Map from Qt -> Open 3D Engine modifiers. + //! Map from Qt -> Open 3D Engine modifiers. inline AZ::u32 TranslateKeyboardModifiers(const Qt::KeyboardModifiers modifiers) { AZ::u32 result = 0; @@ -234,19 +282,19 @@ namespace AzToolsFramework return result; } - /// Interface to translate Qt modifiers to Open 3D Engine modifiers. + //! Interface to translate Qt modifiers to Open 3D Engine modifiers. inline KeyboardModifiers BuildKeyboardModifiers(const Qt::KeyboardModifiers modifiers) { return KeyboardModifiers(TranslateKeyboardModifiers(modifiers)); } - /// Interface to translate Qt buttons to Open 3D Engine buttons. + //! Interface to translate Qt buttons to Open 3D Engine buttons. inline MouseButtons BuildMouseButtons(const Qt::MouseButtons buttons) { return MouseButtons(TranslateMouseButtons(buttons)); } - /// Generate mouse buttons from single button enum. + //! Generate mouse buttons from single button enum. inline MouseButtons MouseButtonsFromButton(MouseButton button) { MouseButtons mouseButtons; @@ -254,7 +302,7 @@ namespace AzToolsFramework return mouseButtons; } - /// Reflect all viewport related types. + //! Reflect all viewport related types. void ViewportInteractionReflect(AZ::ReflectContext* context); } // namespace ViewportInteraction } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp index a7f500cc5f..ed776f90ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorDefaultSelection.h" @@ -30,8 +30,7 @@ namespace AzToolsFramework ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId()); ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect(); - m_manipulatorManager = - AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); + m_manipulatorManager = AZStd::make_shared(AzToolsFramework::g_mainManipulatorManagerId); m_transformComponentSelection = AZStd::make_unique(entityDataCache); } @@ -75,23 +74,18 @@ namespace AzToolsFramework for (const auto& componentModeBuilder : entityAndComponentModeBuilders.m_componentModeBuilders) { m_componentModeCollection.AddComponentMode( - AZ::EntityComponentIdPair( - entityAndComponentModeBuilders.m_entityId, componentModeBuilder.m_componentId), - componentModeBuilder.m_componentType, - componentModeBuilder.m_componentModeBuilder); + AZ::EntityComponentIdPair(entityAndComponentModeBuilders.m_entityId, componentModeBuilder.m_componentId), + componentModeBuilder.m_componentType, componentModeBuilder.m_componentModeBuilder); } } void EditorDefaultSelection::TransitionToComponentMode() { // entering ComponentMode - disable all default actions in the ActionManager - EditorActionRequestBus::Broadcast( - &EditorActionRequests::DisableDefaultActions); + EditorActionRequestBus::Broadcast(&EditorActionRequests::DisableDefaultActions); // attach widget to store ComponentMode specific actions - EditorActionRequestBus::Broadcast( - &EditorActionRequests::AttachOverride, - &PhantomWidget()); + EditorActionRequestBus::Broadcast(&EditorActionRequests::AttachOverride, &PhantomWidget()); if (m_transformComponentSelection) { @@ -103,8 +97,7 @@ namespace AzToolsFramework // refresh button ui ToolsApplicationEvents::Bus::Broadcast( - &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, - PropertyModificationRefreshLevel::Refresh_EntireTree); + &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); } void EditorDefaultSelection::TransitionFromComponentMode() @@ -117,19 +110,16 @@ namespace AzToolsFramework m_transformComponentSelection->RegisterManipulator(); } - EditorActionRequestBus::Broadcast( - &EditorActionRequests::DetachOverride); + EditorActionRequestBus::Broadcast(&EditorActionRequests::DetachOverride); ClearActionOverrides(); // leaving ComponentMode - enable all default actions in ActionManager - EditorActionRequestBus::Broadcast( - &EditorActionRequests::EnableDefaultActions); + EditorActionRequestBus::Broadcast(&EditorActionRequests::EnableDefaultActions); // refresh button ui ToolsApplicationEvents::Bus::Broadcast( - &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, - PropertyModificationRefreshLevel::Refresh_EntireTree); + &ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay, PropertyModificationRefreshLevel::Refresh_EntireTree); } void EditorDefaultSelection::EndComponentMode() @@ -142,8 +132,7 @@ namespace AzToolsFramework m_componentModeCollection.Refresh(entityComponentIdPair); } - bool EditorDefaultSelection::AddedToComponentMode( - const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) + bool EditorDefaultSelection::AddedToComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) { return m_componentModeCollection.AddedToComponentMode(entityComponentIdPair, componentType); } @@ -152,10 +141,10 @@ namespace AzToolsFramework { ComponentModeFramework::ComponentModeDelegateRequestBus::EnumerateHandlers( [componentType](ComponentModeFramework::ComponentModeDelegateRequestBus::InterfaceType* componentModeMouseRequests) - { - componentModeMouseRequests->AddComponentModeOfType(componentType); - return true; - }); + { + componentModeMouseRequests->AddComponentModeOfType(componentType); + return true; + }); TransitionToComponentMode(); } @@ -238,8 +227,7 @@ namespace AzToolsFramework } } - bool EditorDefaultSelection::InternalHandleMouseViewportInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + bool EditorDefaultSelection::InternalHandleMouseViewportInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { bool enterComponentModeAttempted = false; const bool componentModeBefore = InComponentMode(); @@ -249,15 +237,15 @@ namespace AzToolsFramework { // enumerate all ComponentModeDelegateRequestBus and check if any triggered AddComponentModes ComponentModeFramework::ComponentModeDelegateRequestBus::EnumerateHandlers( - [&mouseInteraction, &enterComponentModeAttempted] - (ComponentModeFramework::ComponentModeDelegateRequestBus::InterfaceType* componentModeMouseRequests) - { - // detect if a double click happened on any Component in the viewport, attempting - // to move it into ComponentMode (note: this is not guaranteed to succeed as an - // incompatible multi-selection may prevent it) - enterComponentModeAttempted = componentModeMouseRequests->DetectEnterComponentModeInteraction(mouseInteraction); - return !enterComponentModeAttempted; - }); + [&mouseInteraction, &enterComponentModeAttempted]( + ComponentModeFramework::ComponentModeDelegateRequestBus::InterfaceType* componentModeMouseRequests) + { + // detect if a double click happened on any Component in the viewport, attempting + // to move it into ComponentMode (note: this is not guaranteed to succeed as an + // incompatible multi-selection may prevent it) + enterComponentModeAttempted = componentModeMouseRequests->DetectEnterComponentModeInteraction(mouseInteraction); + return !enterComponentModeAttempted; + }); // here we know ComponentMode was entered successfully and was not prohibited if (m_componentModeCollection.ModesAdded()) @@ -272,25 +260,24 @@ namespace AzToolsFramework else { ComponentModeFramework::ComponentModeRequestBus::EnumerateHandlers( - [&mouseInteraction, &handled] - (ComponentModeFramework::ComponentModeRequestBus::InterfaceType* componentModeRequest) - { - if (componentModeRequest->HandleMouseInteraction(mouseInteraction)) + [&mouseInteraction, &handled](ComponentModeFramework::ComponentModeRequestBus::InterfaceType* componentModeRequest) { - handled = true; - } + if (componentModeRequest->HandleMouseInteraction(mouseInteraction)) + { + handled = true; + } - return true; - }); + return true; + }); if (!handled) { ComponentModeFramework::ComponentModeDelegateRequestBus::EnumerateHandlers( - [&mouseInteraction] - (ComponentModeFramework::ComponentModeDelegateRequestBus::InterfaceType* componentModeDelegateRequests) - { - return !componentModeDelegateRequests->DetectLeaveComponentModeInteraction(mouseInteraction); - }); + [&mouseInteraction]( + ComponentModeFramework::ComponentModeDelegateRequestBus::InterfaceType* componentModeDelegateRequests) + { + return !componentModeDelegateRequests->DetectLeaveComponentModeInteraction(mouseInteraction); + }); } } @@ -311,8 +298,7 @@ namespace AzToolsFramework } void EditorDefaultSelection::DisplayViewportSelection( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { if (m_transformComponentSelection) { @@ -330,8 +316,7 @@ namespace AzToolsFramework } void EditorDefaultSelection::DisplayViewportSelection2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { if (m_transformComponentSelection) { @@ -355,11 +340,12 @@ namespace AzToolsFramework void EditorDefaultSelection::AddActionOverride(const ActionOverride& actionOverride) { // check if an action with this uri is already added - const auto actionIt = AZStd::find_if(m_actions.begin(), m_actions.end(), + const auto actionIt = AZStd::find_if( + m_actions.begin(), m_actions.end(), [actionOverride](const AZStd::shared_ptr& actionOverrideMapping) - { - return actionOverride.m_uri == actionOverrideMapping->m_uri; - }); + { + return actionOverride.m_uri == actionOverrideMapping->m_uri; + }); // if an action with the same uri is already added, store the callback for this action if (actionIt != m_actions.end()) @@ -381,44 +367,45 @@ namespace AzToolsFramework // set callbacks that should happen when this action is triggered auto index = static_cast(m_actions.size()); - QObject::connect(action.get(), &QAction::triggered, [this, index]() - { - const auto vec = m_actions; // increment ref count of shared_ptr, callback may clear actions - for (auto& callback : vec[index]->m_callbacks) + QObject::connect( + action.get(), &QAction::triggered, + [this, index]() { - callback(); - } - }); + const auto vec = m_actions; // increment ref count of shared_ptr, callback may clear actions + for (auto& callback : vec[index]->m_callbacks) + { + callback(); + } + }); - m_actions.emplace_back( - AZStd::make_shared( - actionOverride.m_uri, AZStd::vector>{ actionOverride.m_callback }, - AZStd::move(action))); + m_actions.emplace_back(AZStd::make_shared( + actionOverride.m_uri, AZStd::vector>{ actionOverride.m_callback }, AZStd::move(action))); // register action with edit menu - EditorMenuRequestBus::Broadcast( - &EditorMenuRequests::AddEditMenuAction, m_actions.back()->m_action.get()); + EditorMenuRequestBus::Broadcast(&EditorMenuRequests::AddEditMenuAction, m_actions.back()->m_action.get()); } } void EditorDefaultSelection::ClearActionOverrides() { - AZStd::for_each(m_actions.begin(), m_actions.end(), + AZStd::for_each( + m_actions.begin(), m_actions.end(), [this](const AZStd::shared_ptr& actionMapping) - { - PhantomWidget().removeAction(actionMapping->m_action.get()); - }); + { + PhantomWidget().removeAction(actionMapping->m_action.get()); + }); m_actions.clear(); } void EditorDefaultSelection::RemoveActionOverride(const AZ::Crc32 actionOverrideUri) { - const auto it = AZStd::find_if(m_actions.begin(), m_actions.end(), + const auto it = AZStd::find_if( + m_actions.begin(), m_actions.end(), [actionOverrideUri](const AZStd::shared_ptr& actionMapping) - { - return actionMapping->m_uri == actionOverrideUri; - }); + { + return actionMapping->m_uri == actionOverrideUri; + }); if (it != m_actions.end()) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h index 414e163e2f..d2f2c2fea5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorDefaultSelection.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -19,7 +19,7 @@ namespace AzToolsFramework { - /// The default selection/input handler for the editor (includes handling ComponentMode). + //! The default selection/input handler for the editor (includes handling ComponentMode). class EditorDefaultSelection : public ViewportInteraction::InternalViewportSelectionRequests , private ActionOverrideRequestBus::Handler @@ -28,30 +28,26 @@ namespace AzToolsFramework public: AZ_CLASS_ALLOCATOR_DECL - /// @cond + //! @cond explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache); EditorDefaultSelection(const EditorDefaultSelection&) = delete; EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete; virtual ~EditorDefaultSelection(); - /// @endcond + //! @endcond - /// Override the default widget used to store QActions while in ComponentMode. - /// @note This should not be necessary during normal operation and is provided - /// as a customization point to aid with testing. + //! Override the default widget used to store QActions while in ComponentMode. + //! @note This should not be necessary during normal operation and is provided + //! as a customization point to aid with testing. void SetOverridePhantomWidget(QWidget* phantomOverrideWidget); private: // ViewportInteraction::InternalMouseViewportRequests ... - bool InternalHandleMouseViewportInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - bool InternalHandleMouseManipulatorInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseViewportInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseManipulatorInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; void DisplayViewportSelection( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; void DisplayViewportSelection2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; // ActionOverrideRequestBus ... void SetupActionOverrideHandler(QWidget* parent) override; @@ -65,7 +61,10 @@ namespace AzToolsFramework const AZStd::vector& entityAndComponentModeBuilders) override; void AddComponentModes(const ComponentModeFramework::EntityAndComponentModeBuilders& entityAndComponentModeBuilders) override; void EndComponentMode() override; - bool InComponentMode() override { return m_componentModeCollection.InComponentMode(); } + bool InComponentMode() override + { + return m_componentModeCollection.InComponentMode(); + } void Refresh(const AZ::EntityComponentIdPair& entityComponentIdPair) override; bool AddedToComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType) override; void AddSelectedComponentModesOfType(const AZ::Uuid& componentType) override; @@ -77,41 +76,43 @@ namespace AzToolsFramework bool HasMultipleComponentTypes() override; void RefreshActions() override; - /// Helpers to deal with moving in and out of ComponentMode. + //! Helpers to deal with moving in and out of ComponentMode. void TransitionToComponentMode(); void TransitionFromComponentMode(); - /// Accessor used internally to refer to the phantom widget. - /// This will either be the default widget or the override if non-null. + //! Accessor used internally to refer to the phantom widget. + //! This will either be the default widget or the override if non-null. QWidget& PhantomWidget(); - QWidget m_phantomWidget; ///< The phantom widget responsible for holding QActions while in ComponentMode. - QWidget* m_phantomOverrideWidget = nullptr; ///< It's possible to override the phantom widget in special circumstances (eg testing). - ComponentModeFramework::ComponentModeCollection m_componentModeCollection; ///< Handles all active ComponentMode types. - AZStd::unique_ptr m_transformComponentSelection = nullptr; ///< Viewport selection (responsible for - ///< manipulators and transform modifications). - const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; ///< Reference to cached visible EntityData. + QWidget m_phantomWidget; //!< The phantom widget responsible for holding QActions while in ComponentMode. + QWidget* m_phantomOverrideWidget = nullptr; //!< It's possible to override the phantom widget in special circumstances (eg testing). + ComponentModeFramework::ComponentModeCollection m_componentModeCollection; //!< Handles all active ComponentMode types. + AZStd::unique_ptr m_transformComponentSelection = + nullptr; //!< Viewport selection (responsible for + //!< manipulators and transform modifications). + const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Reference to cached visible EntityData. - /// Mapping between passed ActionOverride (AddActionOverride) and allocated QAction. + //! Mapping between passed ActionOverride (AddActionOverride) and allocated QAction. struct ActionOverrideMapping { ActionOverrideMapping( - const AZ::Crc32 uri, const AZStd::vector>& callbacks, - AZStd::unique_ptr action) + const AZ::Crc32 uri, const AZStd::vector>& callbacks, AZStd::unique_ptr action) : m_uri(uri) , m_callbacks(callbacks) - , m_action(AZStd::move(action)) {} + , m_action(AZStd::move(action)) + { + } - AZ::Crc32 m_uri; ///< Unique identifier for the Action. (In the form 'com.amazon.action.---"). - AZStd::vector> m_callbacks; ///< Callbacks associated with this Action (note: with multi-selections there - ///< will be a callback per Entity/Component). - AZStd::unique_ptr m_action; ///< The QAction associated with the overrideWidget for all ComponentMode actions. + AZ::Crc32 m_uri; //!< Unique identifier for the Action. (In the form 'com.amazon.action.---"). + AZStd::vector> m_callbacks; //!< Callbacks associated with this Action (note: with multi-selections + //!< there will be a callback per Entity/Component). + AZStd::unique_ptr m_action; //!< The QAction associated with the overrideWidget for all ComponentMode actions. }; - AZStd::vector> m_actions; ///< Currently bound actions (corresponding to those set - ///< on the override widget). + AZStd::vector> m_actions; //!< Currently bound actions (corresponding to those set + //!< on the override widget). - AZStd::shared_ptr m_manipulatorManager; ///< The default manipulator manager. - ViewportInteraction::MouseInteraction m_currentInteraction; ///< Current mouse interaction to be used for drawing manipulators. + AZStd::shared_ptr m_manipulatorManager; //!< The default manipulator manager. + ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 31da01fadc..6080f6f7ae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorHelpers.h" @@ -16,21 +16,33 @@ #include #include #include +#include #include #include #include -#include #include -#include +#include AZ_CVAR( - bool, ed_visibility_showAggregateEntitySelectionBounds, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, + ed_visibility_showAggregateEntitySelectionBounds, + false, + nullptr, + AZ::ConsoleFunctorFlags::Null, "Display the aggregate selection bounds for a given entity (the union of all component Aabbs)"); AZ_CVAR( - bool, ed_visibility_showAggregateEntityTransformedLocalBounds, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, + ed_visibility_showAggregateEntityTransformedLocalBounds, + false, + nullptr, + AZ::ConsoleFunctorFlags::Null, "Display the aggregate transformed local bounds for a given entity (the union of all local component Aabbs)"); AZ_CVAR( - bool, ed_visibility_showAggregateEntityWorldBounds, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, + ed_visibility_showAggregateEntityWorldBounds, + false, + nullptr, + AZ::ConsoleFunctorFlags::Null, "Display the aggregate world bounds for a given entity (the union of all world component Aabbs)"); namespace AzToolsFramework @@ -48,8 +60,7 @@ namespace AzToolsFramework static bool HelpersVisible() { bool helpersVisible = false; - EditorRequestBus::BroadcastResult( - helpersVisible, &EditorRequests::DisplayHelpersVisible); + EditorRequestBus::BroadcastResult(helpersVisible, &EditorRequests::DisplayHelpersVisible); return helpersVisible; } @@ -59,25 +70,23 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - return s_iconMinScale + (s_iconMaxScale - s_iconMinScale) * + return s_iconMinScale + + (s_iconMaxScale - s_iconMinScale) * (1.0f - AZ::GetClamp(AZ::GetMax(0.0f, sqrtf(distSq) - s_iconCloseDist) / s_iconFarDist, 0.0f, 1.0f)); } static void DisplayComponents( - const AZ::EntityId entityId, const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AZ::EntityId entityId, const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); AzFramework::EntityDebugDisplayEventBus::Event( - entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, - viewportInfo, debugDisplay); + entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, viewportInfo, debugDisplay); if (ed_visibility_showAggregateEntitySelectionBounds) { - if (const AZ::Aabb aabb = AzToolsFramework::CalculateEditorEntitySelectionBounds(entityId, viewportInfo); - aabb.IsValid()) + if (const AZ::Aabb aabb = AzToolsFramework::CalculateEditorEntitySelectionBounds(entityId, viewportInfo); aabb.IsValid()) { debugDisplay.SetColor(AZ::Colors::Orange); debugDisplay.DrawWireBox(aabb.GetMin(), aabb.GetMax()); @@ -107,8 +116,7 @@ namespace AzToolsFramework } AZ::EntityId EditorHelpers::HandleMouseInteraction( - const AzFramework::CameraState& cameraState, - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -127,8 +135,7 @@ namespace AzToolsFramework { const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex); - if ( m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex) - || !m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex)) + if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex) || !m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex)) { continue; } @@ -148,10 +155,8 @@ namespace AzToolsFramework const auto iconRange = static_cast(GetIconScale(distSqFromCamera) * s_iconSize * 0.5f); const auto screenCoords = mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates; - if ( screenCoords.m_x >= screenPosition.m_x - iconRange - && screenCoords.m_x <= screenPosition.m_x + iconRange - && screenCoords.m_y >= screenPosition.m_y - iconRange - && screenCoords.m_y <= screenPosition.m_y + iconRange) + if (screenCoords.m_x >= screenPosition.m_x - iconRange && screenCoords.m_x <= screenPosition.m_x + iconRange && + screenCoords.m_y >= screenPosition.m_y - iconRange && screenCoords.m_y <= screenPosition.m_y + iconRange) { entityIdUnderCursor = entityId; break; @@ -161,16 +166,13 @@ namespace AzToolsFramework using AzFramework::ViewportInfo; // check if components provide an aabb - if (const AZ::Aabb aabb = CalculateEditorEntitySelectionBounds(entityId, ViewportInfo{viewportId}); - aabb.IsValid()) + if (const AZ::Aabb aabb = CalculateEditorEntitySelectionBounds(entityId, ViewportInfo{ viewportId }); aabb.IsValid()) { // coarse grain check if (AabbIntersectMouseRay(mouseInteraction.m_mouseInteraction, aabb)) { // if success, pick against specific component - if (PickEntity( - entityId, mouseInteraction.m_mouseInteraction, - closestDistance, viewportId)) + if (PickEntity(entityId, mouseInteraction.m_mouseInteraction, closestDistance, viewportId)) { entityIdUnderCursor = entityId; } @@ -182,7 +184,8 @@ namespace AzToolsFramework } void EditorHelpers::DisplayHelpers( - const AzFramework::ViewportInfo& viewportInfo, const AzFramework::CameraState& cameraState, + const AzFramework::ViewportInfo& viewportInfo, + const AzFramework::CameraState& cameraState, AzFramework::DebugDisplayRequests& debugDisplay, const AZStd::function& showIconCheck) { @@ -202,8 +205,8 @@ namespace AzToolsFramework // notify components to display DisplayComponents(entityId, viewportInfo, debugDisplay); - if ( m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) - || (m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId))) + if (m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) || + (m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId))) { continue; } @@ -219,7 +222,8 @@ namespace AzToolsFramework const float iconSize = s_iconSize * iconScale; using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType; - const AZ::Color iconHighlight = [this, entityCacheIndex]() { + const AZ::Color iconHighlight = [this, entityCacheIndex]() + { if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex)) { return AZ::Color(AZ::u8(100), AZ::u8(100), AZ::u8(100), AZ::u8(255)); @@ -233,14 +237,9 @@ namespace AzToolsFramework return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f); }(); - EditorViewportIconDisplay::Get()->DrawIcon({ - viewportInfo.m_viewportId, - iconTextureId, - iconHighlight, - entityPosition, - EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace, - AZ::Vector2{iconSize, iconSize} - }); + EditorViewportIconDisplay::Get()->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition, + EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace, + AZ::Vector2{ iconSize, iconSize } }); } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h index e36203e31d..926cadee34 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -21,7 +21,7 @@ namespace AzFramework class DebugDisplayRequests; struct ViewportInfo; struct CameraState; -} +} // namespace AzFramework namespace AzToolsFramework { @@ -32,37 +32,39 @@ namespace AzToolsFramework struct MouseInteractionEvent; } - /// EditorHelpers are the visualizations that appear for entities - /// when 'Display Helpers' is toggled on inside the editor. - /// These include but are not limited to entity icons and shape visualizations. + //! EditorHelpers are the visualizations that appear for entities + //! when 'Display Helpers' is toggled on inside the editor. + //! These include but are not limited to entity icons and shape visualizations. class EditorHelpers { public: AZ_CLASS_ALLOCATOR_DECL - /// An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to - /// efficiently read entity data without resorting to EBus calls. + //! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to + //! efficiently read entity data without resorting to EBus calls. explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache) - : m_entityDataCache(entityDataCache) {} + : m_entityDataCache(entityDataCache) + { + } EditorHelpers(const EditorHelpers&) = delete; EditorHelpers& operator=(const EditorHelpers&) = delete; ~EditorHelpers() = default; - /// Handle any mouse interaction with the EditorHelpers. - /// Used to check if a particular entity was selected. + //! Handle any mouse interaction with the EditorHelpers. + //! Used to check if a particular entity was selected. AZ::EntityId HandleMouseInteraction( - const AzFramework::CameraState& cameraState, - const ViewportInteraction::MouseInteractionEvent& mouseInteraction); + const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction); - /// Do the drawing responsible for the EditorHelpers. - /// @param showIconCheck Provide a custom callback to filter certain entities from - /// displaying an icon under certain conditions. + //! Do the drawing responsible for the EditorHelpers. + //! @param showIconCheck Provide a custom callback to filter certain entities from + //! displaying an icon under certain conditions. void DisplayHelpers( - const AzFramework::ViewportInfo& viewportInfo, const AzFramework::CameraState& cameraState, + const AzFramework::ViewportInfo& viewportInfo, + const AzFramework::CameraState& cameraState, AzFramework::DebugDisplayRequests& debugDisplay, const AZStd::function& showIconCheck); private: - const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; ///< Entity Data queried by the EditorHelpers. + const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp index 12f10e9784..578e113aaf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorInteractionSystemComponent.h" @@ -45,8 +45,7 @@ namespace AzToolsFramework return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction); } - void EditorInteractionSystemComponent::SetHandler( - const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) + void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) { // when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we // can forward calls to the specific type implementing ViewportSelectionRequests @@ -57,32 +56,30 @@ namespace AzToolsFramework m_entityDataCache = AZStd::make_unique(); - m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, + m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor, // so have to reset before assigning the new one m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get()); } void EditorInteractionSystemComponent::SetDefaultHandler() { - SetHandler([](const EditorVisibleEntityDataCache* entityDataCache) - { - return AZStd::make_unique(entityDataCache); - }); + SetHandler( + [](const EditorVisibleEntityDataCache* entityDataCache) + { + return AZStd::make_unique(entityDataCache); + }); } void EditorInteractionSystemComponent::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() - ->Version(0) - ; + serializeContext->Class()->Version(0); } } void EditorInteractionSystemComponent::DisplayViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -93,8 +90,7 @@ namespace AzToolsFramework } void EditorInteractionSystemComponent::DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { m_interactionRequests->DisplayViewportSelection2d(viewportInfo, debugDisplay); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h index 2205add970..8fba5c923d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -18,9 +18,9 @@ namespace AzToolsFramework { - /// System Component to wrap active input handler. - /// EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport - /// and forwards them to a concrete implementation of ViewportSelectionRequests. + //! System Component to wrap active input handler. + //! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport + //! and forwards them to a concrete implementation of ViewportSelectionRequests. class EditorInteractionSystemComponent : public AZ::Component , private EditorInteractionSystemViewportSelectionRequestBus::Handler @@ -37,18 +37,12 @@ namespace AzToolsFramework void SetDefaultHandler() override; // EditorInteractionSystemViewportSelectionRequestBus ... - bool InternalHandleMouseViewportInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; - bool InternalHandleMouseManipulatorInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseViewportInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseManipulatorInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; // AzFramework::ViewportDebugDisplayEventBus - void DisplayViewport( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; - void DisplayViewport2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; + void DisplayViewport2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; private: // AZ::Component @@ -58,11 +52,11 @@ namespace AzToolsFramework // EditorEventsBus void NotifyCentralWidgetInitialized() override; - AZStd::unique_ptr m_entityDataCache = nullptr; ///< Visible EntityData cache to be used by concrete - ///< instantiations of ViewportSelectionRequests. + AZStd::unique_ptr m_entityDataCache = nullptr; //!< Visible EntityData cache to be used by concrete + //!< instantiations of ViewportSelectionRequests. - AZStd::unique_ptr m_interactionRequests; ///< Hold a concrete implementation of - ///< ViewportSelectionRequests to handle viewport - ///< input and drawing for the Editor. + AZStd::unique_ptr m_interactionRequests; //!< Hold a concrete implementation of + //!< ViewportSelectionRequests to handle viewport + //!< input and drawing for the Editor. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h index 09135069d8..184fa29aa0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,10 +22,9 @@ namespace AzToolsFramework { class EditorVisibleEntityDataCache; - /// Bus to handle all mouse events originating from the viewport. - /// Coordinated by the EditorInteractionSystemComponent - class EditorInteractionSystemViewportSelectionRequests - : public AZ::EBusTraits + //! Bus to handle all mouse events originating from the viewport. + //! Coordinated by the EditorInteractionSystemComponent + class EditorInteractionSystemViewportSelectionRequests : public AZ::EBusTraits { public: using BusIdType = AzFramework::EntityContextId; @@ -36,32 +35,31 @@ namespace AzToolsFramework ~EditorInteractionSystemViewportSelectionRequests() = default; }; - /// Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. + //! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface. using ViewportSelectionRequestsBuilderFn = AZStd::function(const EditorVisibleEntityDataCache*)>; - /// Interface for system component implementing the ViewportSelectionRequests interface. - /// This interface also includes a setter to set a custom handler also implementing - /// the ViewportSelectionRequests interface to customize editor behavior. - class EditorInteractionSystemViewportSelection - : public ViewportInteraction::InternalViewportSelectionRequests + //! Interface for system component implementing the ViewportSelectionRequests interface. + //! This interface also includes a setter to set a custom handler also implementing + //! the ViewportSelectionRequests interface to customize editor behavior. + class EditorInteractionSystemViewportSelection : public ViewportInteraction::InternalViewportSelectionRequests { public: - /// \ref SetHandler takes a factory function to create a new type implementing - /// the ViewportSelectionRequests interface. - /// It provides a handler implementing ViewportSelectionRequests to handle all - /// viewport mouse input and drawing. + //! \ref SetHandler takes a factory function to create a new type implementing + //! the ViewportSelectionRequests interface. + //! It provides a handler implementing ViewportSelectionRequests to handle all + //! viewport mouse input and drawing. virtual void SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) = 0; - /// \ref SetDefaultHandler is a utility function to set the - /// default editor handler (currently \ref EditorDefaultSelection). - /// This is useful to call after setting another mode and then wishing - /// to return to normal operation of the editor. + //! \ref SetDefaultHandler is a utility function to set the + //! default editor handler (currently \ref EditorDefaultSelection). + //! This is useful to call after setting another mode and then wishing + //! to return to normal operation of the editor. virtual void SetDefaultHandler() = 0; }; - /// Type to inherit to implement EditorInteractionSystemViewportSelection. - /// @note Called by viewport events (RenderViewport) and then handled by concrete - /// implementation of InternalViewportSelectionRequests. + //! Type to inherit to implement EditorInteractionSystemViewportSelection. + //! @note Called by viewport events (RenderViewport) and then handled by concrete + //! implementation of InternalViewportSelectionRequests. using EditorInteractionSystemViewportSelectionRequestBus = AZ::EBus; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp index 1be8ee927b..e026c1f9e0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.cpp @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorPickEntitySelection.h" @@ -19,9 +19,8 @@ namespace AzToolsFramework { AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0) - EditorPickEntitySelection::EditorPickEntitySelection( - const EditorVisibleEntityDataCache* entityDataCache) - : m_editorHelpers(AZStd::make_unique(entityDataCache)) + EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache) + : m_editorHelpers(AZStd::make_unique(entityDataCache)) { } @@ -29,8 +28,7 @@ namespace AzToolsFramework { if (m_hoveredEntityId.IsValid()) { - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false); } } @@ -41,8 +39,7 @@ namespace AzToolsFramework // highlighted - hoveredEntityId is an in/out param that is updated based on the change in // entityIdUnderCursor. static void HandleAccents( - const AZ::EntityId entityIdUnderCursor, AZ::EntityId& hoveredEntityId, - const ViewportInteraction::MouseButtons mouseButtons) + const AZ::EntityId entityIdUnderCursor, AZ::EntityId& hoveredEntityId, const ViewportInteraction::MouseButtons mouseButtons) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -55,8 +52,7 @@ namespace AzToolsFramework { if (hoveredEntityId.IsValid()) { - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetEntityHighlighted, hoveredEntityId, false); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, hoveredEntityId, false); hoveredEntityId.SetInvalid(); } @@ -68,8 +64,7 @@ namespace AzToolsFramework { if (entityIdUnderCursor.IsValid() && entityIdUnderCursor != hoveredEntityId) { - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetEntityHighlighted, entityIdUnderCursor, true); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, entityIdUnderCursor, true); hoveredEntityId = entityIdUnderCursor; } @@ -93,8 +88,7 @@ namespace AzToolsFramework if (m_cachedEntityIdUnderCursor.IsValid()) { // if we clicked on a valid entity id, actually try to set it - EditorPickModeRequestBus::Broadcast( - &EditorPickModeRequests::PickModeSelectEntity, m_cachedEntityIdUnderCursor); + EditorPickModeRequestBus::Broadcast(&EditorPickModeRequests::PickModeSelectEntity, m_cachedEntityIdUnderCursor); } // after a click, always stop pick mode, whether we set an entity or not @@ -105,16 +99,18 @@ namespace AzToolsFramework } void EditorPickEntitySelection::DisplayViewportSelection( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { const AzFramework::CameraState cameraState = GetCameraState(viewportInfo.m_viewportId); m_editorHelpers->DisplayHelpers( - viewportInfo, cameraState, debugDisplay, [](AZ::EntityId){ return true; }); + viewportInfo, cameraState, debugDisplay, + [](AZ::EntityId) + { + return true; + }); HandleAccents( - m_cachedEntityIdUnderCursor, m_hoveredEntityId, - ViewportInteraction::BuildMouseButtons(QGuiApplication::mouseButtons())); + m_cachedEntityIdUnderCursor, m_hoveredEntityId, ViewportInteraction::BuildMouseButtons(QGuiApplication::mouseButtons())); } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h index 07aafe2607..2c956e1534 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -17,10 +17,9 @@ namespace AzToolsFramework { - /// Viewport interaction that will handle assigning an entity in the viewport to - /// an entity field in the entity inspector. - class EditorPickEntitySelection - : public ViewportInteraction::InternalViewportSelectionRequests + //! Viewport interaction that will handle assigning an entity in the viewport to + //! an entity field in the entity inspector. + class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests { public: AZ_CLASS_ALLOCATOR_DECL @@ -30,15 +29,12 @@ namespace AzToolsFramework private: // ViewportInteraction::InternalViewportSelectionRequests ... - bool InternalHandleMouseViewportInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseViewportInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) override; void DisplayViewportSelection( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) override; + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override; - AZStd::unique_ptr m_editorHelpers; ///< Editor visualization of entities (icons, shapes, debug visuals etc). - - AZ::EntityId m_hoveredEntityId; ///< What EntityId is the mouse currently hovering over (if any). - AZ::EntityId m_cachedEntityIdUnderCursor; ///< Store the EntityId on each mouse move for use in Display. + AZStd::unique_ptr m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc). + AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any). + AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp index d0143c5517..7856c159ab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.cpp @@ -1,38 +1,36 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorSelectionUtil.h" -#include -#include -#include #include +#include +#include +#include #include #include #include namespace AzToolsFramework { - /// Default ray length for picking in the viewport. + // default ray length for picking in the viewport static const float s_pickRayLength = 1000.0f; - AZ::Vector3 CalculateCenterOffset( - const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot) + AZ::Vector3 CalculateCenterOffset(const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot) { if (Centered(pivot)) { const AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId); - if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entity); - localBound.IsValid()) + if (const AZ::Aabb localBound = AzFramework::CalculateEntityLocalBoundsUnion(entity); localBound.IsValid()) { return localBound.GetCenter(); } @@ -41,76 +39,71 @@ namespace AzToolsFramework return AZ::Vector3::CreateZero(); } - float CalculateScreenToWorldMultiplier( - const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) + float CalculateScreenToWorldMultiplier(const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) { const float apparentDistance = 10.0f; // compute the distance from the camera, projected onto the camera's forward direction // note: this keeps the scale value the same when positions are at the edge of the screen - const float projectedCameraDistance = - std::abs((cameraState.m_position - worldPosition).Dot(cameraState.m_forward)); + const float projectedCameraDistance = std::abs((cameraState.m_position - worldPosition).Dot(cameraState.m_forward)); // author sizes of bounds/manipulators as they would appear // in perspective 10 meters from the camera. return AZ::GetMax(projectedCameraDistance, cameraState.m_nearClip) / apparentDistance; } - AzFramework::ScreenPoint GetScreenPosition(const int viewportId, const AZ::Vector3& worldTranslation) + AzFramework::ScreenPoint GetScreenPosition(const int viewportId, const AZ::Vector3& worldTranslation) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); auto screenPosition = AzFramework::ScreenPoint(0, 0); ViewportInteraction::ViewportInteractionRequestBus::EventResult( - screenPosition, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::ViewportWorldToScreen, + screenPosition, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::ViewportWorldToScreen, worldTranslation); return screenPosition; } - bool AabbIntersectMouseRay( - const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb) + bool AabbIntersectMouseRay(const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - const AZ::Vector3 rayScaledDir = - mouseInteraction.m_mousePick.m_rayDirection * s_pickRayLength; + const AZ::Vector3 rayScaledDir = mouseInteraction.m_mousePick.m_rayDirection * s_pickRayLength; AZ::Vector3 startNormal; float t, end; return AZ::Intersect::IntersectRayAABB( - mouseInteraction.m_mousePick.m_rayOrigin, rayScaledDir, - rayScaledDir.GetReciprocal(), aabb, t, end, startNormal) > 0; + mouseInteraction.m_mousePick.m_rayOrigin, rayScaledDir, rayScaledDir.GetReciprocal(), aabb, t, end, startNormal) > 0; } bool PickEntity( - const AZ::EntityId entityId, const ViewportInteraction::MouseInteraction& mouseInteraction, - float& closestDistance, const int viewportId) + const AZ::EntityId entityId, + const ViewportInteraction::MouseInteraction& mouseInteraction, + float& closestDistance, + const int viewportId) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity); bool entityPicked = false; EditorComponentSelectionRequestsBus::EnumerateHandlersId( - entityId, [mouseInteraction, &entityPicked, &closestDistance, viewportId] - (EditorComponentSelectionRequests* handler) -> bool - { - if (handler->SupportsEditorRayIntersect()) + entityId, + [mouseInteraction, &entityPicked, &closestDistance, viewportId](EditorComponentSelectionRequests* handler) -> bool { - float distance = std::numeric_limits::max(); - const bool intersection = handler->EditorSelectionIntersectRayViewport( - { viewportId }, mouseInteraction.m_mousePick.m_rayOrigin, - mouseInteraction.m_mousePick.m_rayDirection, distance); - - if (intersection && distance < closestDistance) + if (handler->SupportsEditorRayIntersect()) { - entityPicked = true; - closestDistance = distance; - } - } + float distance = std::numeric_limits::max(); + const bool intersection = handler->EditorSelectionIntersectRayViewport( + { viewportId }, mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection, distance); - return true; // iterate over all handlers - }); + if (intersection && distance < closestDistance) + { + entityPicked = true; + closestDistance = distance; + } + } + + return true; // iterate over all handlers + }); return entityPicked; } @@ -119,9 +112,8 @@ namespace AzToolsFramework { AzFramework::CameraState cameraState; ViewportInteraction::ViewportInteractionRequestBus::EventResult( - cameraState, viewportId, - &ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState); - + cameraState, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState); + return cameraState; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h index e904277078..a7c6368d65 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorSelectionUtil.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -30,56 +30,53 @@ namespace AzFramework namespace AzToolsFramework { - /// Is the pivot at the center of the object (middle of extents) or at the - /// exported authored object root position. + //! Is the pivot at the center of the object (middle of extents) or at the + //! exported authored object root position. inline bool Centered(const EditorTransformComponentSelectionRequests::Pivot pivot) { return pivot == EditorTransformComponentSelectionRequests::Pivot::Center; } - /// Return offset from object pivot to center if center is true, otherwise Vector3::Zero. + //! Return offset from object pivot to center if center is true, otherwise Vector3::Zero. AZ::Vector3 CalculateCenterOffset(AZ::EntityId entityId, EditorTransformComponentSelectionRequests::Pivot pivot); - /// Calculate scale factor based on distance from camera - float CalculateScreenToWorldMultiplier( - const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState); + //! Calculate scale factor based on distance from camera + float CalculateScreenToWorldMultiplier(const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState); - /// Map from world space to screen space. - AzFramework::ScreenPoint GetScreenPosition(int viewportId, const AZ::Vector3& worldTranslation); + //! Map from world space to screen space. + AzFramework::ScreenPoint GetScreenPosition(int viewportId, const AZ::Vector3& worldTranslation); - /// Given a mouse interaction, determine if the pick ray from its position - /// in screen space intersected an aabb in world space. - bool AabbIntersectMouseRay( - const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb); + //! Given a mouse interaction, determine if the pick ray from its position + //! in screen space intersected an aabb in world space. + bool AabbIntersectMouseRay(const ViewportInteraction::MouseInteraction& mouseInteraction, const AZ::Aabb& aabb); - /// Return if a mouse interaction (pick ray) did intersect the tested EntityId. + //! Return if a mouse interaction (pick ray) did intersect the tested EntityId. bool PickEntity( - AZ::EntityId entityId, const ViewportInteraction::MouseInteraction& mouseInteraction, - float& closestDistance, int viewportId); + AZ::EntityId entityId, const ViewportInteraction::MouseInteraction& mouseInteraction, float& closestDistance, int viewportId); - /// Wrapper for EBus call to return the CameraState for a given viewport. + //! Wrapper for EBus call to return the CameraState for a given viewport. AzFramework::CameraState GetCameraState(int viewportId); - /// Wrapper for EBus call to return the DPI scaling for a given viewport. - float GetScreenDisplayScaling(const int viewportId); + //! Wrapper for EBus call to return the DPI scaling for a given viewport. + float GetScreenDisplayScaling(int viewportId); - /// A utility to return the center of several points. - /// Take several positions and store the min and max of each in - /// turn - when all points have been added return the center/midpoint. + //! A utility to return the center of several points. + //! Take several positions and store the min and max of each in + //! turn - when all points have been added return the center/midpoint. class MidpointCalculator { public: - /// Default constructed with min and max initialized to opposites. + //! Default constructed with min and max initialized to opposites. MidpointCalculator() = default; - /// Call this for all positions you want to be considered. + //! Call this for all positions you want to be considered. void AddPosition(const AZ::Vector3& position) { m_minPosition = position.GetMin(m_minPosition); m_maxPosition = position.GetMax(m_maxPosition); } - /// Once all positions have been added, call this to return the midpoint. + //! Once all positions have been added, call this to return the midpoint. AZ::Vector3 CalculateMidpoint() const { return m_minPosition + (m_maxPosition - m_minPosition) * 0.5f; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 5603c1a0f7..fee0267766 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -1,29 +1,30 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorTransformComponentSelection.h" -#include #include #include #include #include +#include #include #include #include #include -#include +#include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -47,20 +47,40 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR_IMPL(EditorTransformComponentSelection, AZ::SystemAllocator, 0) AZ_CVAR( - float, cl_viewportGizmoAxisLineWidth, 4.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + cl_viewportGizmoAxisLineWidth, + 4.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The width of the line for the viewport axis gizmo"); AZ_CVAR( - float, cl_viewportGizmoAxisLineLength, 0.7f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + cl_viewportGizmoAxisLineLength, + 0.7f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The length of the line for the viewport axis gizmo"); AZ_CVAR( - float, cl_viewportGizmoAxisLabelOffset, 1.15f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + cl_viewportGizmoAxisLabelOffset, + 1.15f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The offset of the label for the viewport axis gizmo"); AZ_CVAR( - float, cl_viewportGizmoAxisLabelSize, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, + cl_viewportGizmoAxisLabelSize, + 1.0f, + nullptr, + AZ::ConsoleFunctorFlags::Null, "The size of each label for the viewport axis gizmo"); AZ_CVAR( - AZ::Vector2, cl_viewportGizmoAxisScreenPosition, AZ::Vector2(0.045f, 0.9f), nullptr, - AZ::ConsoleFunctorFlags::Null, "The screen position of the gizmo in normalized (0-1) ndc space"); + AZ::Vector2, + cl_viewportGizmoAxisScreenPosition, + AZ::Vector2(0.045f, 0.9f), + nullptr, + AZ::ConsoleFunctorFlags::Null, + "The screen position of the gizmo in normalized (0-1) ndc space"); // strings related to new viewport interaction model (EditorTransformComponentSelection) static const char* const s_togglePivotTitleRightClick = "Toggle pivot"; @@ -125,7 +145,8 @@ namespace AzToolsFramework static const int s_defaultViewportId = 0; - static const float s_pivotSize = 0.075f; ///< The size of the pivot (box) to render when selected. + static const float s_pivotSize = 0.075f; // the size of the pivot (box) to render when selected + // data passed to manipulators when processing mouse interactions // m_entityIds should be sorted based on the entity hierarchy // (see SortEntitiesByLocationInHierarchy and BuildSortedEntityIdVectorFromEntityIdContainer) @@ -146,8 +167,7 @@ namespace AzToolsFramework bool OptionalFrame::HasTransformOverride() const { - return m_translationOverride.has_value() - || m_orientationOverride.has_value(); + return m_translationOverride.has_value() || m_orientationOverride.has_value(); } bool OptionalFrame::HasEntityOverride() const @@ -226,7 +246,7 @@ namespace AzToolsFramework return mouseInteraction.m_mouseInteraction.m_mouseButtons.Middle() && mouseInteraction.m_mouseEvent == ViewportInteraction::MouseEvent::Down && (mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Alt() || - mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl()); + mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl()); } static bool ManipulatorDitto(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) @@ -263,8 +283,7 @@ namespace AzToolsFramework } } - static EditorTransformComponentSelectionRequests::Pivot TogglePivotMode( - const EditorTransformComponentSelectionRequests::Pivot pivot) + static EditorTransformComponentSelectionRequests::Pivot TogglePivotMode(const EditorTransformComponentSelectionRequests::Pivot pivot) { switch (pivot) { @@ -282,8 +301,7 @@ namespace AzToolsFramework template static AZStd::vector EntityIdVectorFromContainer(const EntityIdContainer& entityIdContainer) { - static_assert(AZStd::is_same::value, - "Container type is not an EntityId"); + static_assert(AZStd::is_same::value, "Container type is not an EntityId"); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); return AZStd::vector(entityIdContainer.begin(), entityIdContainer.end()); @@ -293,8 +311,7 @@ namespace AzToolsFramework template static AZStd::vector EntityIdVectorFromMap(const EntityIdMap& entityIdMap) { - static_assert(AZStd::is_same::value, - "Container key type is not an EntityId"); + static_assert(AZStd::is_same::value, "Container key type is not an EntityId"); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -318,10 +335,15 @@ namespace AzToolsFramework template static void BoxSelectAddRemoveToEntitySelection( - const AZStd::optional& boxSelect, const AzFramework::ScreenPoint& screenPosition, const AZ::EntityId visibleEntityId, - const EntityIdContainer& incomingEntityIds, EntityIdContainer& outgoingEntityIds, + const AZStd::optional& boxSelect, + const AzFramework::ScreenPoint& screenPosition, + const AZ::EntityId visibleEntityId, + const EntityIdContainer& incomingEntityIds, + EntityIdContainer& outgoingEntityIds, EditorTransformComponentSelection& entityTransformComponentSelection, - EntitySelectFuncType selectFunc1, EntitySelectFuncType selectFunc2, Compare outgoingCheck) + EntitySelectFuncType selectFunc1, + EntitySelectFuncType selectFunc2, + Compare outgoingCheck) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -349,10 +371,14 @@ namespace AzToolsFramework template static void EntityBoxSelectUpdateGeneral( - const AZStd::optional& boxSelect, EditorTransformComponentSelection& editorTransformComponentSelection, - const EntityIdContainer& activeSelectedEntityIds, EntityIdContainer& selectedEntityIdsBeforeBoxSelect, - EntityIdContainer& potentialSelectedEntityIds, EntityIdContainer& potentialDeselectedEntityIds, - const EditorVisibleEntityDataCache& entityDataCache, const int viewportId, + const AZStd::optional& boxSelect, + EditorTransformComponentSelection& editorTransformComponentSelection, + const EntityIdContainer& activeSelectedEntityIds, + EntityIdContainer& selectedEntityIdsBeforeBoxSelect, + EntityIdContainer& potentialSelectedEntityIds, + EntityIdContainer& potentialDeselectedEntityIds, + const EditorVisibleEntityDataCache& entityDataCache, + const int viewportId, const ViewportInteraction::KeyboardModifiers currentKeyboardModifiers, const ViewportInteraction::KeyboardModifiers& previousKeyboardModifiers) { @@ -382,8 +408,7 @@ namespace AzToolsFramework for (size_t entityCacheIndex = 0; entityCacheIndex < entityDataCache.VisibleEntityDataCount(); ++entityCacheIndex) { - if ( entityDataCache.IsVisibleEntityLocked(entityCacheIndex) - || !entityDataCache.IsVisibleEntityVisible(entityCacheIndex)) + if (entityDataCache.IsVisibleEntityLocked(entityCacheIndex) || !entityDataCache.IsVisibleEntityVisible(entityCacheIndex)) { continue; } @@ -396,10 +421,8 @@ namespace AzToolsFramework if (currentKeyboardModifiers.Ctrl()) { BoxSelectAddRemoveToEntitySelection( - boxSelect, screenPosition, entityId, - selectedEntityIdsBeforeBoxSelect, potentialDeselectedEntityIds, - editorTransformComponentSelection, - &EditorTransformComponentSelection::RemoveEntityFromSelection, + boxSelect, screenPosition, entityId, selectedEntityIdsBeforeBoxSelect, potentialDeselectedEntityIds, + editorTransformComponentSelection, &EditorTransformComponentSelection::RemoveEntityFromSelection, &EditorTransformComponentSelection::AddEntityToSelection, [](const typename EntityIdContainer::const_iterator entityId, const EntityIdContainer& entityIds) { @@ -409,10 +432,8 @@ namespace AzToolsFramework else { BoxSelectAddRemoveToEntitySelection( - boxSelect, screenPosition, entityId, - activeSelectedEntityIds, potentialSelectedEntityIds, - editorTransformComponentSelection, - &EditorTransformComponentSelection::AddEntityToSelection, + boxSelect, screenPosition, entityId, activeSelectedEntityIds, potentialSelectedEntityIds, + editorTransformComponentSelection, &EditorTransformComponentSelection::AddEntityToSelection, &EditorTransformComponentSelection::RemoveEntityFromSelection, [](const typename EntityIdContainer::const_iterator entityId, const EntityIdContainer& entityIds) { @@ -429,62 +450,53 @@ namespace AzToolsFramework for (auto& entityIdLookup : entityIdManipulators.m_lookups) { - entityIdLookup.second.m_initial = - AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first)); + entityIdLookup.second.m_initial = AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first)); } } static void DestroyCluster(const ViewportUi::ClusterId clusterId) { ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, - clusterId); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, clusterId); } static void SetViewportUiClusterVisible(const ViewportUi::ClusterId clusterId, const bool visible) { ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, - clusterId, visible); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, clusterId, visible); } static void SetViewportUiClusterActiveButton(const ViewportUi::ClusterId clusterId, const ViewportUi::ButtonId buttonId) { ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, - clusterId, buttonId); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, clusterId, buttonId); } static ViewportUi::ButtonId RegisterClusterButton(const ViewportUi::ClusterId clusterId, const char* iconName) { ViewportUi::ButtonId buttonId; ViewportUi::ViewportUiRequestBus::EventResult( - buttonId, ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, - clusterId, AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName)); + buttonId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateClusterButton, clusterId, + AZStd::string::format(":/stylesheet/img/UI20/toolbar/%s.svg", iconName)); return buttonId; } // return either center or entity pivot - static AZ::Vector3 CalculatePivotTranslation( - const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot) + static AZ::Vector3 CalculatePivotTranslation(const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); return worldFromLocal.TransformPoint(CalculateCenterOffset(entityId, pivot)); } void EditorTransformComponentSelection::UpdateSpaceCluster(const ReferenceFrame referenceFrame) { - auto buttonIdFromFrameFn = [this](const ReferenceFrame referenceFrame) { + auto buttonIdFromFrameFn = [this](const ReferenceFrame referenceFrame) + { switch (referenceFrame) { case ReferenceFrame::Local: @@ -498,14 +510,13 @@ namespace AzToolsFramework }; ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, m_spaceCluster.m_spaceClusterId, - buttonIdFromFrameFn(referenceFrame)); + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, + m_spaceCluster.m_spaceClusterId, buttonIdFromFrameFn(referenceFrame)); } namespace ETCS { - PivotOrientationResult CalculatePivotOrientation( - const AZ::EntityId entityId, const ReferenceFrame referenceFrame) + PivotOrientationResult CalculatePivotOrientation(const AZ::EntityId entityId, const ReferenceFrame referenceFrame) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -515,21 +526,17 @@ namespace AzToolsFramework switch (referenceFrame) { case ReferenceFrame::Local: - AZ::TransformBus::EventResult( - result.m_worldOrientation, entityId, - &AZ::TransformBus::Events::GetWorldRotationQuaternion); + AZ::TransformBus::EventResult(result.m_worldOrientation, entityId, &AZ::TransformBus::Events::GetWorldRotationQuaternion); break; case ReferenceFrame::Parent: { AZ::EntityId parentId; - AZ::TransformBus::EventResult( - parentId, entityId, &AZ::TransformBus::Events::GetParentId); + AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId); if (parentId.IsValid()) { AZ::TransformBus::EventResult( - result.m_worldOrientation, parentId, - &AZ::TransformBus::Events::GetWorldRotationQuaternion); + result.m_worldOrientation, parentId, &AZ::TransformBus::Events::GetWorldRotationQuaternion); result.m_parentId = parentId; } @@ -559,8 +566,7 @@ namespace AzToolsFramework { // check if this entity has a parent AZ::EntityId parentId; - AZ::TransformBus::EventResult( - parentId, entityIdLookupIt->first, &AZ::TransformBus::Events::GetParentId); + AZ::TransformBus::EventResult(parentId, entityIdLookupIt->first, &AZ::TransformBus::Events::GetParentId); // if no parent, space will be world, terminate if (!parentId.IsValid()) @@ -575,9 +581,7 @@ namespace AzToolsFramework if (!commonParentId.IsValid()) { commonParentId = parentId; - AZ::TransformBus::EventResult( - result.m_worldOrientation, parentId, - &AZ::TransformBus::Events::GetWorldRotationQuaternion); + AZ::TransformBus::EventResult(result.m_worldOrientation, parentId, &AZ::TransformBus::Events::GetWorldRotationQuaternion); } // if we know we still have a parent in common @@ -602,8 +606,7 @@ namespace AzToolsFramework static AZ::Vector3 CalculatePivotTranslationForEntityIds( const EntityIdMap& entityIdMap, const EditorTransformComponentSelectionRequests::Pivot pivot) { - static_assert(AZStd::is_same::value, - "Container key type is not an EntityId"); + static_assert(AZStd::is_same::value, "Container key type is not an EntityId"); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -628,11 +631,9 @@ namespace AzToolsFramework namespace ETCS { template - PivotOrientationResult CalculatePivotOrientationForEntityIds( - const EntityIdMap& entityIdMap, const ReferenceFrame referenceFrame) + PivotOrientationResult CalculatePivotOrientationForEntityIds(const EntityIdMap& entityIdMap, const ReferenceFrame referenceFrame) { - static_assert(AZStd::is_same::value, - "Container key type is not an EntityId"); + static_assert(AZStd::is_same::value, "Container key type is not an EntityId"); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -660,12 +661,11 @@ namespace AzToolsFramework { template PivotOrientationResult CalculateSelectionPivotOrientation( - const EntityIdMap& entityIdMap, const OptionalFrame& pivotOverrideFrame, - const ReferenceFrame referenceFrame) + const EntityIdMap& entityIdMap, const OptionalFrame& pivotOverrideFrame, const ReferenceFrame referenceFrame) { - static_assert(AZStd::is_same::value, - "Container key type is not an EntityId"); - static_assert(AZStd::is_same::value, + static_assert(AZStd::is_same::value, "Container key type is not an EntityId"); + static_assert( + AZStd::is_same::value, "Container value type is not an EntityIdManipulators::Lookup"); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -728,20 +728,16 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - return pivotOverrideFrame.m_translationOverride.value_or( - CalculatePivotTranslationForEntityIds(entityIdMap, pivot)); + return pivotOverrideFrame.m_translationOverride.value_or(CalculatePivotTranslationForEntityIds(entityIdMap, pivot)); } template static AZ::Quaternion RecalculateAverageManipulatorOrientation( - const EntityIdMap& entityIdMap, - const OptionalFrame& pivotOverrideFrame, - const ReferenceFrame referenceFrame) + const EntityIdMap& entityIdMap, const OptionalFrame& pivotOverrideFrame, const ReferenceFrame referenceFrame) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - return ETCS::CalculateSelectionPivotOrientation( - entityIdMap, pivotOverrideFrame, referenceFrame).m_worldOrientation; + return ETCS::CalculateSelectionPivotOrientation(entityIdMap, pivotOverrideFrame, referenceFrame).m_worldOrientation; } template @@ -756,15 +752,12 @@ namespace AzToolsFramework // return final transform, if we have an override for translation use that, otherwise // use centered translation of selection return AZ::Transform::CreateFromQuaternionAndTranslation( - RecalculateAverageManipulatorOrientation( - entityIdMap, pivotOverrideFrame, referenceFrame), - RecalculateAverageManipulatorTranslation( - entityIdMap, pivotOverrideFrame, pivot)); + RecalculateAverageManipulatorOrientation(entityIdMap, pivotOverrideFrame, referenceFrame), + RecalculateAverageManipulatorTranslation(entityIdMap, pivotOverrideFrame, pivot)); } template - static void BuildSortedEntityIdVectorFromEntityIdMap( - const EntityIdMap& entityIds, EntityIdList& sortedEntityIdsOut) + static void BuildSortedEntityIdVectorFromEntityIdMap(const EntityIdMap& entityIds, EntityIdList& sortedEntityIdsOut) { sortedEntityIdsOut = EntityIdVectorFromMap(entityIds); SortEntitiesByLocationInHierarchy(sortedEntityIdsOut); @@ -777,8 +770,7 @@ namespace AzToolsFramework for (auto& entityIdLookup : entityManipulators.m_lookups) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); entityIdLookup.second.m_initial = worldFromLocal; } @@ -804,11 +796,13 @@ namespace AzToolsFramework template static void UpdateTranslationManipulator( - const Action& action, const EntityIdContainer& entityIdContainer, + const Action& action, + const EntityIdContainer& entityIdContainer, EntityIdManipulators& entityIdManipulators, OptionalFrame& pivotOverrideFrame, ViewportInteraction::KeyboardModifiers& prevModifiers, - bool& transformChangedInternally, const AZStd::optional spaceLock) + bool& transformChangedInternally, + const AZStd::optional spaceLock) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -817,8 +811,7 @@ namespace AzToolsFramework if (action.m_modifiers.Ctrl()) { // moving with ctrl - setting override - pivotOverrideFrame.m_translationOverride = - entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + pivotOverrideFrame.m_translationOverride = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); InitializeTranslationLookup(entityIdManipulators); } else @@ -827,8 +820,7 @@ namespace AzToolsFramework // note: used for parent and world depending on the current reference frame const auto pivotOrientation = - ETCS::CalculateSelectionPivotOrientation( - entityIdManipulators.m_lookups, pivotOverrideFrame, referenceFrame); + ETCS::CalculateSelectionPivotOrientation(entityIdManipulators.m_lookups, pivotOverrideFrame, referenceFrame); // note: must use sorted entityIds based on hierarchy order when updating transforms for (AZ::EntityId entityId : entityIdContainer) @@ -847,46 +839,37 @@ namespace AzToolsFramework { // move in each entities local space at once AZ::Quaternion worldOrientation = AZ::Quaternion::CreateIdentity(); - AZ::TransformBus::EventResult( - worldOrientation, entityId, &AZ::TransformBus::Events::GetWorldRotationQuaternion); + AZ::TransformBus::EventResult(worldOrientation, entityId, &AZ::TransformBus::Events::GetWorldRotationQuaternion); - const AZ::Transform space = - entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse() * - AZ::Transform::CreateFromQuaternionAndTranslation( - worldOrientation, worldTranslation); + const AZ::Transform space = entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse() * + AZ::Transform::CreateFromQuaternionAndTranslation(worldOrientation, worldTranslation); - const AZ::Vector3 localOffset = space.TransformVector(action.LocalPositionOffset()); + const AZ::Vector3 localOffset = space.TransformVector(action.LocalPositionOffset()); if (action.m_modifiers != prevModifiers) { - entityItLookupIt->second.m_initial = - AZ::Transform::CreateTranslation(worldTranslation - localOffset); + entityItLookupIt->second.m_initial = AZ::Transform::CreateTranslation(worldTranslation - localOffset); } ETCS::SetEntityWorldTranslation( - entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, - transformChangedInternally); + entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, transformChangedInternally); } break; case ReferenceFrame::Parent: case ReferenceFrame::World: { - AZ::Quaternion offsetRotation = - pivotOrientation.m_worldOrientation * - QuaternionFromTransformNoScaling( - entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse()); + AZ::Quaternion offsetRotation = pivotOrientation.m_worldOrientation * + QuaternionFromTransformNoScaling(entityIdManipulators.m_manipulators->GetLocalTransform().GetInverse()); const AZ::Vector3 localOffset = offsetRotation.TransformVector(action.LocalPositionOffset()); if (action.m_modifiers != prevModifiers) { - entityItLookupIt->second.m_initial = - AZ::Transform::CreateTranslation(worldTranslation - localOffset); + entityItLookupIt->second.m_initial = AZ::Transform::CreateTranslation(worldTranslation - localOffset); } ETCS::SetEntityWorldTranslation( - entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, - transformChangedInternally); + entityId, entityItLookupIt->second.m_initial.GetTranslation() + localOffset, transformChangedInternally); } break; } @@ -895,8 +878,7 @@ namespace AzToolsFramework // if transform pivot override has been set, make sure to update it when we move it if (pivotOverrideFrame.m_translationOverride) { - pivotOverrideFrame.m_translationOverride = - entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + pivotOverrideFrame.m_translationOverride = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); } } @@ -904,8 +886,10 @@ namespace AzToolsFramework } static void HandleAccents( - const bool hasSelectedEntities, const AZ::EntityId entityIdUnderCursor, - const bool ctrlHeld, AZ::EntityId& hoveredEntityId, + const bool hasSelectedEntities, + const AZ::EntityId entityIdUnderCursor, + const bool ctrlHeld, + AZ::EntityId& hoveredEntityId, const ViewportInteraction::MouseButtons mouseButtons, const bool usingBoxSelect) { @@ -914,13 +898,11 @@ namespace AzToolsFramework const bool invalidMouseButtonHeld = mouseButtons.Middle() || mouseButtons.Right(); if ((hoveredEntityId.IsValid() && hoveredEntityId != entityIdUnderCursor) || - (hasSelectedEntities && !ctrlHeld && hoveredEntityId.IsValid()) || - invalidMouseButtonHeld) + (hasSelectedEntities && !ctrlHeld && hoveredEntityId.IsValid()) || invalidMouseButtonHeld) { if (hoveredEntityId.IsValid()) { - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetEntityHighlighted, hoveredEntityId, false); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, hoveredEntityId, false); hoveredEntityId.SetInvalid(); } @@ -930,8 +912,7 @@ namespace AzToolsFramework { if (entityIdUnderCursor.IsValid()) { - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetEntityHighlighted, entityIdUnderCursor, true); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, entityIdUnderCursor, true); hoveredEntityId = entityIdUnderCursor; } @@ -946,15 +927,13 @@ namespace AzToolsFramework // get unsnapped terrain position (world space) AZ::Vector3 worldSurfacePosition; ViewportInteraction::MainEditorViewportInteractionRequestBus::EventResult( - worldSurfacePosition, viewportId, - &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::PickTerrain, + worldSurfacePosition, viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::PickTerrain, mouseInteraction.m_mousePick.m_screenCoordinates); // convert to local space - snap if enabled const GridSnapParameters gridSnapParams = GridSnapSettings(viewportId); const AZ::Vector3 finalSurfacePosition = gridSnapParams.m_gridSnap - ? CalculateSnappedTerrainPosition( - worldSurfacePosition, AZ::Transform::CreateIdentity(), viewportId, gridSnapParams.m_gridSize) + ? CalculateSnappedTerrainPosition(worldSurfacePosition, AZ::Transform::CreateIdentity(), viewportId, gridSnapParams.m_gridSize) : worldSurfacePosition; return finalSurfacePosition; @@ -981,10 +960,9 @@ namespace AzToolsFramework for (AZ::EntityId entityId : entityIds) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); - transformsBefore.insert({ entityId, worldFromLocal }); + transformsBefore.insert({ entityId, worldFromLocal }); } return transformsBefore; @@ -992,8 +970,7 @@ namespace AzToolsFramework // ask the visible entity data cache if the entity is selectable in the viewport // (useful in the context of drawing when we only care about entities we can see) - static bool SelectableInVisibleViewportCache( - const EditorVisibleEntityDataCache& entityDataCache, const AZ::EntityId entityId) + static bool SelectableInVisibleViewportCache(const EditorVisibleEntityDataCache& entityDataCache, const AZ::EntityId entityId) { if (auto entityIndex = entityDataCache.GetVisibleEntityIndexFromId(entityId)) { @@ -1021,15 +998,12 @@ namespace AzToolsFramework // is handled internally - this call is often required after an action/shortcut of some kind static void RefreshUiAfterChange(const EntityIdList& entitiyIds) { - EditorTransformChangeNotificationBus::Broadcast( - &EditorTransformChangeNotifications::OnEntityTransformChanged, entitiyIds); + EditorTransformChangeNotificationBus::Broadcast(&EditorTransformChangeNotifications::OnEntityTransformChanged, entitiyIds); - ToolsApplicationNotificationBus::Broadcast( - &ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); + ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values); } - EditorTransformComponentSelection::EditorTransformComponentSelection( - const EditorVisibleEntityDataCache* entityDataCache) + EditorTransformComponentSelection::EditorTransformComponentSelection(const EditorVisibleEntityDataCache* entityDataCache) : m_entityDataCache(entityDataCache) { const AzFramework::EntityContextId entityContextId = GetEntityContextId(); @@ -1090,101 +1064,96 @@ namespace AzToolsFramework m_boxSelect.InstallLeftMouseDown( [this, entityBoxSelectData](const ViewportInteraction::MouseInteractionEvent& /*mouseInteraction*/) - { - // begin selection undo/redo command - entityBoxSelectData->m_boxSelectSelectionCommand = - AZStd::make_unique(EntityIdList(), s_entityBoxSelectUndoRedoDesc); - // grab currently selected entities - entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect = m_selectedEntityIds; - }); + { + // begin selection undo/redo command + entityBoxSelectData->m_boxSelectSelectionCommand = + AZStd::make_unique(EntityIdList(), s_entityBoxSelectUndoRedoDesc); + // grab currently selected entities + entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect = m_selectedEntityIds; + }); m_boxSelect.InstallMouseMove( [this, entityBoxSelectData](const ViewportInteraction::MouseInteractionEvent& mouseInteraction) - { - EntityBoxSelectUpdateGeneral( - m_boxSelect.BoxRegion(), *this, m_selectedEntityIds, entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect, - entityBoxSelectData->m_potentialSelectedEntityIds, entityBoxSelectData->m_potentialDeselectedEntityIds, - *m_entityDataCache, mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId, - mouseInteraction.m_mouseInteraction.m_keyboardModifiers, - m_boxSelect.PreviousModifiers()); - }); + { + EntityBoxSelectUpdateGeneral( + m_boxSelect.BoxRegion(), *this, m_selectedEntityIds, entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect, + entityBoxSelectData->m_potentialSelectedEntityIds, entityBoxSelectData->m_potentialDeselectedEntityIds, + *m_entityDataCache, mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId, + mouseInteraction.m_mouseInteraction.m_keyboardModifiers, m_boxSelect.PreviousModifiers()); + }); m_boxSelect.InstallLeftMouseUp( [this, entityBoxSelectData]() - { - entityBoxSelectData->m_boxSelectSelectionCommand->UpdateSelection(EntityIdVectorFromContainer(m_selectedEntityIds)); - - // if we know a change in selection has occurred, record the undo step - if ( !entityBoxSelectData->m_potentialDeselectedEntityIds.empty() - || !entityBoxSelectData->m_potentialSelectedEntityIds.empty()) { - ScopedUndoBatch undoBatch(s_entityBoxSelectUndoRedoDesc); + entityBoxSelectData->m_boxSelectSelectionCommand->UpdateSelection(EntityIdVectorFromContainer(m_selectedEntityIds)); - // restore manipulator overrides when undoing - if (m_entityIdManipulators.m_manipulators && m_selectedEntityIds.empty()) + // if we know a change in selection has occurred, record the undo step + if (!entityBoxSelectData->m_potentialDeselectedEntityIds.empty() || + !entityBoxSelectData->m_potentialSelectedEntityIds.empty()) { - CreateEntityManipulatorDeselectCommand(undoBatch); + ScopedUndoBatch undoBatch(s_entityBoxSelectUndoRedoDesc); + + // restore manipulator overrides when undoing + if (m_entityIdManipulators.m_manipulators && m_selectedEntityIds.empty()) + { + CreateEntityManipulatorDeselectCommand(undoBatch); + } + + entityBoxSelectData->m_boxSelectSelectionCommand->SetParent(undoBatch.GetUndoBatch()); + entityBoxSelectData->m_boxSelectSelectionCommand.release(); + + SetSelectedEntities(EntityIdVectorFromContainer(m_selectedEntityIds)); + // note: manipulators will be updated in AfterEntitySelectionChanged + + // clear pivot override when selection is empty + if (m_selectedEntityIds.empty()) + { + m_pivotOverrideFrame.Reset(); + } + } + else + { + entityBoxSelectData->m_boxSelectSelectionCommand.reset(); } - entityBoxSelectData->m_boxSelectSelectionCommand->SetParent(undoBatch.GetUndoBatch()); - entityBoxSelectData->m_boxSelectSelectionCommand.release(); - - SetSelectedEntities(EntityIdVectorFromContainer(m_selectedEntityIds)); - // note: manipulators will be updated in AfterEntitySelectionChanged - - // clear pivot override when selection is empty - if (m_selectedEntityIds.empty()) - { - m_pivotOverrideFrame.Reset(); - } - } - else - { - entityBoxSelectData->m_boxSelectSelectionCommand.reset(); - } - - entityBoxSelectData->m_potentialSelectedEntityIds.clear(); - entityBoxSelectData->m_potentialDeselectedEntityIds.clear(); - entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.clear(); - }); + entityBoxSelectData->m_potentialSelectedEntityIds.clear(); + entityBoxSelectData->m_potentialDeselectedEntityIds.clear(); + entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.clear(); + }); m_boxSelect.InstallDisplayScene( - [this, entityBoxSelectData] - (const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) - { - const auto modifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); - - if (m_boxSelect.PreviousModifiers() != modifiers) + [this, entityBoxSelectData](const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { - EntityBoxSelectUpdateGeneral( - m_boxSelect.BoxRegion(), *this, m_selectedEntityIds, - entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect, - entityBoxSelectData->m_potentialSelectedEntityIds, - entityBoxSelectData->m_potentialDeselectedEntityIds, - *m_entityDataCache, viewportInfo.m_viewportId, modifiers, - m_boxSelect.PreviousModifiers()); - } + const auto modifiers = ViewportInteraction::KeyboardModifiers( + ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); - debugDisplay.DepthTestOff(); - debugDisplay.SetColor(s_selectedEntityAabbColor); - - for (AZ::EntityId entityId : entityBoxSelectData->m_potentialSelectedEntityIds) - { - const auto entityIdIt = entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.find(entityId); - - // don't show box when re-adding from previous selection - if (entityIdIt != entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.end()) + if (m_boxSelect.PreviousModifiers() != modifiers) { - continue; + EntityBoxSelectUpdateGeneral( + m_boxSelect.BoxRegion(), *this, m_selectedEntityIds, entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect, + entityBoxSelectData->m_potentialSelectedEntityIds, entityBoxSelectData->m_potentialDeselectedEntityIds, + *m_entityDataCache, viewportInfo.m_viewportId, modifiers, m_boxSelect.PreviousModifiers()); } - const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); - debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax()); - } + debugDisplay.DepthTestOff(); + debugDisplay.SetColor(s_selectedEntityAabbColor); - debugDisplay.DepthTestOn(); - }); + for (AZ::EntityId entityId : entityBoxSelectData->m_potentialSelectedEntityIds) + { + const auto entityIdIt = entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.find(entityId); + + // don't show box when re-adding from previous selection + if (entityIdIt != entityBoxSelectData->m_selectedEntityIdsBeforeBoxSelect.end()) + { + continue; + } + + const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); + debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax()); + } + + debugDisplay.DepthTestOn(); + }); } EntityManipulatorCommand::State EditorTransformComponentSelection::CreateManipulatorCommandStateFromSelf() const @@ -1197,14 +1166,9 @@ namespace AzToolsFramework return {}; } - return { - BuildPivotOverride( - m_pivotOverrideFrame.HasTranslationOverride(), - m_pivotOverrideFrame.HasOrientationOverride()), - TransformNormalizedScale( - m_entityIdManipulators.m_manipulators->GetLocalTransform()), - m_pivotOverrideFrame.m_pickedEntityIdOverride - }; + return { BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()), + TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform()), + m_pivotOverrideFrame.m_pickedEntityIdOverride }; } void EditorTransformComponentSelection::BeginRecordManipulatorCommand() @@ -1214,14 +1178,13 @@ namespace AzToolsFramework // we must have an existing parent undo batch active when beginning to record // a manipulator command UndoSystem::URSequencePoint* currentUndoOperation = nullptr; - ToolsApplicationRequests::Bus::BroadcastResult( - currentUndoOperation, &ToolsApplicationRequests::GetCurrentUndoBatch); + ToolsApplicationRequests::Bus::BroadcastResult(currentUndoOperation, &ToolsApplicationRequests::GetCurrentUndoBatch); if (currentUndoOperation) { // check here if translation or orientation override are set - m_manipulatorMoveCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + m_manipulatorMoveCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); } } @@ -1234,10 +1197,11 @@ namespace AzToolsFramework m_manipulatorMoveCommand->SetManipulatorAfter(CreateManipulatorCommandStateFromSelf()); UndoSystem::URSequencePoint* currentUndoOperation = nullptr; - ToolsApplicationRequests::Bus::BroadcastResult( - currentUndoOperation, &ToolsApplicationRequests::GetCurrentUndoBatch); + ToolsApplicationRequests::Bus::BroadcastResult(currentUndoOperation, &ToolsApplicationRequests::GetCurrentUndoBatch); - AZ_Assert(currentUndoOperation, "The only way we should have reached this block is if " + AZ_Assert( + currentUndoOperation, + "The only way we should have reached this block is if " "m_manipulatorMoveCommand was created by calling BeginRecordManipulatorMouseMoveCommand. " "If we've reached this point and currentUndoOperation is null, something bad has happened " "in the undo system"); @@ -1254,18 +1218,15 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - AZStd::unique_ptr translationManipulators = - AZStd::make_unique( - TranslationManipulators::Dimensions::Three, - AZ::Transform::CreateIdentity(), AZ::Vector3::CreateOne()); + AZStd::unique_ptr translationManipulators = AZStd::make_unique( + TranslationManipulators::Dimensions::Three, AZ::Transform::CreateIdentity(), AZ::Vector3::CreateOne()); InitializeManipulators(*translationManipulators); ConfigureTranslationManipulatorAppearance3d(&*translationManipulators); translationManipulators->SetLocalTransform( - RecalculateAverageManipulatorTransform( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); + RecalculateAverageManipulatorTransform(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); // lambdas capture shared_ptr by value to increment ref count auto manipulatorEntityIds = AZStd::make_shared(); @@ -1277,95 +1238,92 @@ namespace AzToolsFramework // linear translationManipulators->InstallLinearManipulatorMouseDownCallback( [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable - { - // important to sort entityIds based on hierarchy order when updating transforms - BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); + { + // important to sort entityIds based on hierarchy order when updating transforms + BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators); + InitializeTranslationLookup(m_entityIdManipulators); - m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); - // [ref 1.] - BeginRecordManipulatorCommand(); - }); + // [ref 1.] + BeginRecordManipulatorCommand(); + }); ViewportInteraction::KeyboardModifiers prevModifiers{}; translationManipulators->InstallLinearManipulatorMouseMoveCallback( [this, prevModifiers, manipulatorEntityIds](const LinearManipulator::Action& action) mutable -> void - { - UpdateTranslationManipulator( - action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, + { + UpdateTranslationManipulator( + action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally, m_spaceCluster.m_spaceLock); - }); + }); translationManipulators->InstallLinearManipulatorMouseUpCallback( [this]([[maybe_unused]] const LinearManipulator::Action& action) mutable - { - EndRecordManipulatorCommand(); - }); + { + EndRecordManipulatorCommand(); + }); // planar translationManipulators->InstallPlanarManipulatorMouseDownCallback( [this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action) - { - // important to sort entityIds based on hierarchy order when updating transforms - BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); + { + // important to sort entityIds based on hierarchy order when updating transforms + BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators); + InitializeTranslationLookup(m_entityIdManipulators); - m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); - // [ref 1.] - BeginRecordManipulatorCommand(); - }); + // [ref 1.] + BeginRecordManipulatorCommand(); + }); translationManipulators->InstallPlanarManipulatorMouseMoveCallback( [this, prevModifiers, manipulatorEntityIds](const PlanarManipulator::Action& action) mutable -> void - { - UpdateTranslationManipulator( - action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, + { + UpdateTranslationManipulator( + action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally, m_spaceCluster.m_spaceLock); - }); + }); translationManipulators->InstallPlanarManipulatorMouseUpCallback( [this, manipulatorEntityIds](const PlanarManipulator::Action& /*action*/) - { - EndRecordManipulatorCommand(); - }); + { + EndRecordManipulatorCommand(); + }); // surface translationManipulators->InstallSurfaceManipulatorMouseDownCallback( [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action) - { - BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); + { + BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); - InitializeTranslationLookup(m_entityIdManipulators); + InitializeTranslationLookup(m_entityIdManipulators); - m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); - // [ref 1.] - BeginRecordManipulatorCommand(); - }); + // [ref 1.] + BeginRecordManipulatorCommand(); + }); translationManipulators->InstallSurfaceManipulatorMouseMoveCallback( [this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable -> void - { - UpdateTranslationManipulator( - action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, + { + UpdateTranslationManipulator( + action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers, m_transformChangedInternally, m_spaceCluster.m_spaceLock); - }); + }); translationManipulators->InstallSurfaceManipulatorMouseUpCallback( [this, manipulatorEntityIds](const SurfaceManipulator::Action& /*action*/) - { - EndRecordManipulatorCommand(); - }); + { + EndRecordManipulatorCommand(); + }); // transfer ownership m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators); @@ -1381,18 +1339,12 @@ namespace AzToolsFramework InitializeManipulators(*rotationManipulators); rotationManipulators->SetLocalTransform( - RecalculateAverageManipulatorTransform( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); + RecalculateAverageManipulatorTransform(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); // view - rotationManipulators->SetLocalAxes( - AZ::Vector3::CreateAxisX(), - AZ::Vector3::CreateAxisY(), - AZ::Vector3::CreateAxisZ()); + rotationManipulators->SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); rotationManipulators->ConfigureView( - 2.0f, - AzFramework::ViewportColors::XAxisColor, - AzFramework::ViewportColors::YAxisColor, + 2.0f, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor); struct SharedRotationState @@ -1403,149 +1355,139 @@ namespace AzToolsFramework }; // lambdas capture shared_ptr by value to increment ref count - AZStd::shared_ptr sharedRotationState = - AZStd::make_shared(); + AZStd::shared_ptr sharedRotationState = AZStd::make_shared(); rotationManipulators->InstallLeftMouseDownCallback( [this, sharedRotationState](const AngularManipulator::Action& /*action*/) mutable -> void - { - sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); - sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame; - // important to sort entityIds based on hierarchy order when updating transforms - BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, sharedRotationState->m_entityIds); - - for (auto& entityIdLookup : m_entityIdManipulators.m_lookups) { - AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); + sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity(); + sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame; + // important to sort entityIds based on hierarchy order when updating transforms + BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, sharedRotationState->m_entityIds); - entityIdLookup.second.m_initial = worldFromLocal; - } + for (auto& entityIdLookup : m_entityIdManipulators.m_lookups) + { + AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); - m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + entityIdLookup.second.m_initial = worldFromLocal; + } - // [ref 1.] - BeginRecordManipulatorCommand(); - }); + m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); + + // [ref 1.] + BeginRecordManipulatorCommand(); + }); ViewportInteraction::KeyboardModifiers prevModifiers{}; rotationManipulators->InstallMouseMoveCallback( - [this, prevModifiers, sharedRotationState] - (const AngularManipulator::Action& action) mutable -> void - { - const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers)); - const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; - // store the pivot override frame when positioning the manipulator manually (ctrl) - // so we don't lose the orientation when adding/removing entities from the selection - if (action.m_modifiers.Ctrl()) + [this, prevModifiers, sharedRotationState](const AngularManipulator::Action& action) mutable -> void { - m_pivotOverrideFrame.m_orientationOverride = manipulatorOrientation; - } + const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(action.m_modifiers)); + const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta; + // store the pivot override frame when positioning the manipulator manually (ctrl) + // so we don't lose the orientation when adding/removing entities from the selection + if (action.m_modifiers.Ctrl()) + { + m_pivotOverrideFrame.m_orientationOverride = manipulatorOrientation; + } - // only update the manipulator orientation if we're rotating in a local reference frame or we're - // manually modifying the manipulator orientation independent of the entity by holding ctrl - if ((sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local - && m_entityIdManipulators.m_lookups.size() == 1) || action.m_modifiers.Ctrl()) - { - m_entityIdManipulators.m_manipulators->SetLocalTransform( - AZ::Transform::CreateFromQuaternionAndTranslation( - manipulatorOrientation, - m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); - } + // only update the manipulator orientation if we're rotating in a local reference frame or we're + // manually modifying the manipulator orientation independent of the entity by holding ctrl + if ((sharedRotationState->m_referenceFrameAtMouseDown == ReferenceFrame::Local && + m_entityIdManipulators.m_lookups.size() == 1) || + action.m_modifiers.Ctrl()) + { + m_entityIdManipulators.m_manipulators->SetLocalTransform(AZ::Transform::CreateFromQuaternionAndTranslation( + manipulatorOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); + } - // save state if we change the type of rotation we're doing to to prevent snapping - if (prevModifiers != action.m_modifiers) - { - UpdateInitialRotation(m_entityIdManipulators); - sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); - } + // save state if we change the type of rotation we're doing to to prevent snapping + if (prevModifiers != action.m_modifiers) + { + UpdateInitialRotation(m_entityIdManipulators); + sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); + } - // allow the user to modify the orientation without moving the object if ctrl is held - if (action.m_modifiers.Ctrl()) - { - UpdateInitialRotation(m_entityIdManipulators); - sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); - } - else - { - const auto pivotOrientation = - ETCS::CalculateSelectionPivotOrientation( + // allow the user to modify the orientation without moving the object if ctrl is held + if (action.m_modifiers.Ctrl()) + { + UpdateInitialRotation(m_entityIdManipulators); + sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull(); + } + else + { + const auto pivotOrientation = ETCS::CalculateSelectionPivotOrientation( m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, ReferenceFrame::Parent); - // note: must use sorted entityIds based on hierarchy order when updating transforms - for (AZ::EntityId entityId : sharedRotationState->m_entityIds) - { - auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(entityId); - if (entityIdLookupIt == m_entityIdManipulators.m_lookups.end()) + // note: must use sorted entityIds based on hierarchy order when updating transforms + for (AZ::EntityId entityId : sharedRotationState->m_entityIds) { - continue; - } - - // make sure we take into account how we move the axis independent of object - // if Ctrl was held to adjust the orientation of the axes separately - const AZ::Transform offsetRotation = AZ::Transform::CreateFromQuaternion( - sharedRotationState->m_savedOrientation * action.m_current.m_delta); - - switch (referenceFrame) - { - case ReferenceFrame::Local: + auto entityIdLookupIt = m_entityIdManipulators.m_lookups.find(entityId); + if (entityIdLookupIt == m_entityIdManipulators.m_lookups.end()) { - const AZ::Quaternion rotation = entityIdLookupIt->second.m_initial.GetRotation().GetNormalized(); - const AZ::Vector3 position = entityIdLookupIt->second.m_initial.GetTranslation(); - const float scale = entityIdLookupIt->second.m_initial.GetUniformScale(); - - const AZ::Vector3 centerOffset = CalculateCenterOffset(entityId, m_pivotMode); - - // scale -> rotate -> translate - SetEntityWorldTransform( - entityId, - AZ::Transform::CreateTranslation(position) * - AZ::Transform::CreateFromQuaternion(rotation) * - AZ::Transform::CreateTranslation(centerOffset) * offsetRotation * - AZ::Transform::CreateTranslation(-centerOffset) * - AZ::Transform::CreateUniformScale(scale)); + continue; } - break; - case ReferenceFrame::Parent: + + // make sure we take into account how we move the axis independent of object + // if Ctrl was held to adjust the orientation of the axes separately + const AZ::Transform offsetRotation = + AZ::Transform::CreateFromQuaternion(sharedRotationState->m_savedOrientation * action.m_current.m_delta); + + switch (referenceFrame) { - const AZ::Transform pivotTransform = - AZ::Transform::CreateFromQuaternionAndTranslation( + case ReferenceFrame::Local: + { + const AZ::Quaternion rotation = entityIdLookupIt->second.m_initial.GetRotation().GetNormalized(); + const AZ::Vector3 position = entityIdLookupIt->second.m_initial.GetTranslation(); + const float scale = entityIdLookupIt->second.m_initial.GetUniformScale(); + + const AZ::Vector3 centerOffset = CalculateCenterOffset(entityId, m_pivotMode); + + // scale -> rotate -> translate + SetEntityWorldTransform( + entityId, + AZ::Transform::CreateTranslation(position) * AZ::Transform::CreateFromQuaternion(rotation) * + AZ::Transform::CreateTranslation(centerOffset) * offsetRotation * + AZ::Transform::CreateTranslation(-centerOffset) * AZ::Transform::CreateUniformScale(scale)); + } + break; + case ReferenceFrame::Parent: + { + const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation( pivotOrientation.m_worldOrientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()); - const AZ::Transform transformInPivotSpace = - pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial; + const AZ::Transform transformInPivotSpace = + pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial; - SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace); - } - break; - case ReferenceFrame::World: - { - const AZ::Transform pivotTransform = - AZ::Transform::CreateFromQuaternionAndTranslation( + SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace); + } + break; + case ReferenceFrame::World: + { + const AZ::Transform pivotTransform = AZ::Transform::CreateFromQuaternionAndTranslation( AZ::Quaternion::CreateIdentity(), m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()); - const AZ::Transform transformInPivotSpace = - pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial; + const AZ::Transform transformInPivotSpace = + pivotTransform.GetInverse() * entityIdLookupIt->second.m_initial; - SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace); + SetEntityWorldTransform(entityId, pivotTransform * offsetRotation * transformInPivotSpace); + } + break; } - break; } } - } - prevModifiers = action.m_modifiers; - }); + prevModifiers = action.m_modifiers; + }); rotationManipulators->InstallLeftMouseUpCallback( [this](const AngularManipulator::Action& /*action*/) - { - EndRecordManipulatorCommand(); - }); + { + EndRecordManipulatorCommand(); + }); rotationManipulators->Register(g_mainManipulatorManagerId); @@ -1557,30 +1499,20 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - AZStd::unique_ptr scaleManipulators = - AZStd::make_unique(AZ::Transform::CreateIdentity()); + AZStd::unique_ptr scaleManipulators = AZStd::make_unique(AZ::Transform::CreateIdentity()); InitializeManipulators(*scaleManipulators); scaleManipulators->SetLocalTransform( - RecalculateAverageManipulatorTransform( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); + RecalculateAverageManipulatorTransform(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); - scaleManipulators->SetAxes( - AZ::Vector3::CreateAxisX(), - AZ::Vector3::CreateAxisY(), - AZ::Vector3::CreateAxisZ()); - scaleManipulators->ConfigureView( - 2.0f, - AZ::Color::CreateOne(), - AZ::Color::CreateOne(), - AZ::Color::CreateOne()); + scaleManipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + scaleManipulators->ConfigureView(2.0f, AZ::Color::CreateOne(), AZ::Color::CreateOne(), AZ::Color::CreateOne()); // lambdas capture shared_ptr by value to increment ref count auto manipulatorEntityIds = AZStd::make_shared(); - auto uniformLeftMouseDownCallback = - [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) + auto uniformLeftMouseDownCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) { // important to sort entityIds based on hierarchy order when updating transforms BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds); @@ -1588,22 +1520,19 @@ namespace AzToolsFramework for (auto& entityIdLookup : m_entityIdManipulators.m_lookups) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityIdLookup.first, &AZ::TransformBus::Events::GetWorldTM); entityIdLookup.second.m_initial = worldFromLocal; } m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - m_axisPreview.m_orientation = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); }; auto uniformLeftMouseUpCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) { - m_entityIdManipulators.m_manipulators->SetLocalTransform( - RecalculateAverageManipulatorTransform( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); + m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform( + m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); }; auto uniformLeftMouseMoveCallback = [this, manipulatorEntityIds](const LinearManipulator::Action& action) @@ -1620,7 +1549,8 @@ namespace AzToolsFramework const AZ::Transform initial = entityIdLookupIt->second.m_initial; const float initialScale = initial.GetUniformScale(); - const auto sumVectorElements = [](const AZ::Vector3& vec) { + const auto sumVectorElements = [](const AZ::Vector3& vec) + { return vec.GetX() + vec.GetY() + vec.GetZ(); }; @@ -1630,19 +1560,16 @@ namespace AzToolsFramework if (action.m_modifiers.Alt()) { - const AZ::Transform pivotTransform = TransformNormalizedScale( - entityIdLookupIt->second.m_initial); - const AZ::Transform transformInPivotSpace = - pivotTransform.GetInverse() * initial; + const AZ::Transform pivotTransform = TransformNormalizedScale(entityIdLookupIt->second.m_initial); + const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial; SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace); } else { - const AZ::Transform pivotTransform = TransformNormalizedScale( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); - const AZ::Transform transformInPivotSpace = - pivotTransform.GetInverse() * initial; + const AZ::Transform pivotTransform = + TransformNormalizedScale(m_entityIdManipulators.m_manipulators->GetLocalTransform()); + const AZ::Transform transformInPivotSpace = pivotTransform.GetInverse() * initial; SetEntityWorldTransform(entityId, pivotTransform * scaleTransform * transformInPivotSpace); } @@ -1674,11 +1601,10 @@ namespace AzToolsFramework { if (IsSelectableInViewport(entityId)) { - const AZ::ComponentId transformComponentId = GetTransformComponentId(entityId); + const AZ::ComponentId transformComponentId = GetTransformComponentId(entityId); if (transformComponentId != AZ::InvalidComponentId) { - manipulators.AddEntityComponentIdPair( - AZ::EntityComponentIdPair(entityId, transformComponentId)); + manipulators.AddEntityComponentIdPair(AZ::EntityComponentIdPair(entityId, transformComponentId)); m_entityIdManipulators.m_lookups.insert_key(entityId); } } @@ -1692,11 +1618,10 @@ namespace AzToolsFramework { if (IsSelectableInViewport(entityId)) { - const AZ::ComponentId transformComponentId = GetTransformComponentId(entityId); + const AZ::ComponentId transformComponentId = GetTransformComponentId(entityId); if (transformComponentId != AZ::InvalidComponentId) { - manipulators.AddEntityComponentIdPair( - AZ::EntityComponentIdPair(entityId, transformComponentId)); + manipulators.AddEntityComponentIdPair(AZ::EntityComponentIdPair(entityId, transformComponentId)); m_entityIdManipulators.m_lookups.insert_key(entityId); } } @@ -1754,8 +1679,7 @@ namespace AzToolsFramework CreateEntityManipulatorDeselectCommand(undoBatch); } - auto selectionCommand = - AZStd::make_unique(nextEntityIds, s_entityDeselectUndoRedoDesc); + auto selectionCommand = AZStd::make_unique(nextEntityIds, s_entityDeselectUndoRedoDesc); selectionCommand->SetParent(undoBatch.GetUndoBatch()); selectionCommand.release(); @@ -1785,8 +1709,7 @@ namespace AzToolsFramework return false; } - bool EditorTransformComponentSelection::HandleMouseInteraction( - const ViewportInteraction::MouseInteractionEvent& mouseInteraction) + bool EditorTransformComponentSelection::HandleMouseInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -1816,17 +1739,15 @@ namespace AzToolsFramework } AZ::Transform worldFromLocal; - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); const AZ::Vector3 boxPosition = worldFromLocal.TransformPoint(CalculateCenterOffset(entityId, m_pivotMode)); - const AZ::Vector3 scaledSize = AZ::Vector3(s_pivotSize) * - CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); + const AZ::Vector3 scaledSize = + AZ::Vector3(s_pivotSize) * CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); if (AabbIntersectMouseRay( - mouseInteraction.m_mouseInteraction, - AZ::Aabb::CreateFromMinMax(boxPosition - scaledSize, boxPosition + scaledSize))) + mouseInteraction.m_mouseInteraction, AZ::Aabb::CreateFromMinMax(boxPosition - scaledSize, boxPosition + scaledSize))) { m_cachedEntityIdUnderCursor = entityId; } @@ -1834,16 +1755,15 @@ namespace AzToolsFramework const AZ::EntityId entityIdUnderCursor = m_cachedEntityIdUnderCursor; - EditorContextMenuUpdate( - m_contextMenu, mouseInteraction); + EditorContextMenuUpdate(m_contextMenu, mouseInteraction); m_boxSelect.HandleMouseInteraction(mouseInteraction); if (Input::CycleManipulator(mouseInteraction)) { const size_t scrollBound = 2; - const auto nextMode = (static_cast(m_mode) + scrollBound + - (MouseWheelDelta(mouseInteraction) < 0.0f ? 1 : -1)) % scrollBound; + const auto nextMode = + (static_cast(m_mode) + scrollBound + (MouseWheelDelta(mouseInteraction) < 0.0f ? 1 : -1)) % scrollBound; SetTransformMode(static_cast(nextMode)); @@ -1883,8 +1803,7 @@ namespace AzToolsFramework if (entityIdUnderCursor.IsValid()) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); switch (m_mode) { @@ -1912,8 +1831,7 @@ namespace AzToolsFramework if (entityIdUnderCursor.IsValid()) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); switch (m_mode) { @@ -1938,15 +1856,14 @@ namespace AzToolsFramework // try snapping to the terrain (if in Translation mode) and entity wasn't picked if (Input::SnapTerrain(mouseInteraction)) { - for(AZ::EntityId entityId : m_selectedEntityIds) + for (AZ::EntityId entityId : m_selectedEntityIds) { ScopedUndoBatch::MarkEntityDirty(entityId); } if (m_mode == Mode::Translation) { - const AZ::Vector3 finalSurfacePosition = - PickTerrainPosition(mouseInteraction.m_mouseInteraction); + const AZ::Vector3 finalSurfacePosition = PickTerrainPosition(mouseInteraction.m_mouseInteraction); // handle modifier alternatives if (Input::IndividualDitto(mouseInteraction)) @@ -1958,7 +1875,7 @@ namespace AzToolsFramework CopyTranslationToSelectedEntitiesGroup(finalSurfacePosition); } } - else if(m_mode == Mode::Rotation) + else if (m_mode == Mode::Rotation) { // handle modifier alternatives if (Input::IndividualDitto(mouseInteraction)) @@ -1981,14 +1898,13 @@ namespace AzToolsFramework { ScopedUndoBatch undoBatch(s_dittoManipulatorUndoRedoDesc); - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); if (entityIdUnderCursor.IsValid()) { AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM); // set orientation/translation to match picked entity switch (m_mode) @@ -2029,13 +1945,9 @@ namespace AzToolsFramework DelegateClearManipulatorOverride(); } - manipulatorCommand->SetManipulatorAfter( - EntityManipulatorCommand::State( - BuildPivotOverride( - m_pivotOverrideFrame.HasTranslationOverride(), - m_pivotOverrideFrame.HasOrientationOverride()), - m_entityIdManipulators.m_manipulators->GetLocalTransform(), - entityIdUnderCursor)); + manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State( + BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()), + m_entityIdManipulators.m_manipulators->GetLocalTransform(), entityIdUnderCursor)); manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); manipulatorCommand.release(); @@ -2073,9 +1985,7 @@ namespace AzToolsFramework QObject::connect(actions.back().get(), &QAction::triggered, actions.back().get(), callback); - EditorActionRequestBus::Broadcast( - &EditorActionRequests::AddActionViaBus, - actionId, actions.back().get()); + EditorActionRequestBus::Broadcast(&EditorActionRequests::AddActionViaBus, actionId, actions.back().get()); } void EditorTransformComponentSelection::OnEscape() @@ -2090,18 +2000,17 @@ namespace AzToolsFramework AZ::ComponentApplicationBus::Broadcast( &AZ::ComponentApplicationRequests::EnumerateEntities, [&func](const AZ::Entity* entity) - { - const AZ::EntityId entityId = entity->GetId(); - - bool editorEntity = false; - EditorEntityContextRequestBus::BroadcastResult( - editorEntity, &EditorEntityContextRequests::IsEditorEntity, entityId); - - if (editorEntity) { - func(entityId); - } - }); + const AZ::EntityId entityId = entity->GetId(); + + bool editorEntity = false; + EditorEntityContextRequestBus::BroadcastResult(editorEntity, &EditorEntityContextRequests::IsEditorEntity, entityId); + + if (editorEntity) + { + func(entityId); + } + }); } void EditorTransformComponentSelection::DelegateClearManipulatorOverride() @@ -2149,22 +2058,22 @@ namespace AzToolsFramework }; // lock selection - AddAction(m_actions, { QKeySequence(Qt::Key_L) }, - /*ID_EDIT_FREEZE =*/ 32900, - s_lockSelectionTitle, s_lockSelectionDesc, + AddAction( + m_actions, { QKeySequence(Qt::Key_L) }, + /*ID_EDIT_FREEZE =*/32900, s_lockSelectionTitle, s_lockSelectionDesc, [lockUnlock]() - { - lockUnlock(true); - }); + { + lockUnlock(true); + }); // unlock selection - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::Key_L) }, - /*ID_EDIT_UNFREEZE =*/ 32973, - s_lockSelectionTitle, s_lockSelectionDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::Key_L) }, + /*ID_EDIT_UNFREEZE =*/32973, s_lockSelectionTitle, s_lockSelectionDesc, [lockUnlock]() - { - lockUnlock(false); - }); + { + lockUnlock(false); + }); const auto showHide = [this](const bool show) { @@ -2189,145 +2098,148 @@ namespace AzToolsFramework }; // hide selection - AddAction(m_actions, { QKeySequence(Qt::Key_H) }, - /*ID_EDIT_HIDE =*/ 32898, - s_hideSelectionTitle, s_hideSelectionDesc, + AddAction( + m_actions, { QKeySequence(Qt::Key_H) }, + /*ID_EDIT_HIDE =*/32898, s_hideSelectionTitle, s_hideSelectionDesc, [showHide]() - { - showHide(false); - }); + { + showHide(false); + }); // show selection - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::Key_H) }, - /*ID_EDIT_UNHIDE =*/ 32974, - s_hideSelectionTitle, s_hideSelectionDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::Key_H) }, + /*ID_EDIT_UNHIDE =*/32974, s_hideSelectionTitle, s_hideSelectionDesc, [showHide]() - { - showHide(true); - }); + { + showHide(true); + }); // unlock all entities in the level/scene - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L) }, - /*ID_EDIT_UNFREEZEALL =*/ 32901, - s_unlockAllTitle, s_unlockAllDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L) }, + /*ID_EDIT_UNFREEZEALL =*/32901, s_unlockAllTitle, s_unlockAllDesc, []() - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - - ScopedUndoBatch undoBatch(s_unlockAllUndoRedoDesc); - - EnumerateEditorEntities([](AZ::EntityId entityId) { - ScopedUndoBatch::MarkEntityDirty(entityId); - SetEntityLockState(entityId, false); + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + + ScopedUndoBatch undoBatch(s_unlockAllUndoRedoDesc); + + EnumerateEditorEntities( + [](AZ::EntityId entityId) + { + ScopedUndoBatch::MarkEntityDirty(entityId); + SetEntityLockState(entityId, false); + }); }); - }); // show all entities in the level/scene - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_H) }, - /*ID_EDIT_UNHIDEALL =*/ 32899, - s_showAllTitle, s_showAllDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_H) }, + /*ID_EDIT_UNHIDEALL =*/32899, s_showAllTitle, s_showAllDesc, []() - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - - ScopedUndoBatch undoBatch(s_showAllEntitiesUndoRedoDesc); - - EnumerateEditorEntities([](AZ::EntityId entityId) { - ScopedUndoBatch::MarkEntityDirty(entityId); - SetEntityVisibility(entityId, true); + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + + ScopedUndoBatch undoBatch(s_showAllEntitiesUndoRedoDesc); + + EnumerateEditorEntities( + [](AZ::EntityId entityId) + { + ScopedUndoBatch::MarkEntityDirty(entityId); + SetEntityVisibility(entityId, true); + }); }); - }); // select all entities in the level/scene - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::Key_A) }, - /*ID_EDIT_SELECTALL =*/ 33376, - s_selectAllTitle, s_selectAllDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::Key_A) }, + /*ID_EDIT_SELECTALL =*/33376, s_selectAllTitle, s_selectAllDesc, [this]() - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - - ScopedUndoBatch undoBatch(s_selectAllEntitiesUndoRedoDesc); - - if (m_entityIdManipulators.m_manipulators) { - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - // note, nothing will change that the manipulatorCommand needs to keep track - // for after so no need to call SetManipulatorAfter + ScopedUndoBatch undoBatch(s_selectAllEntitiesUndoRedoDesc); - manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); - manipulatorCommand.release(); - } - - EnumerateEditorEntities([this](AZ::EntityId entityId) - { - if (IsSelectableInViewport(entityId)) + if (m_entityIdManipulators.m_manipulators) { - AddEntityToSelection(entityId); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + + // note, nothing will change that the manipulatorCommand needs to keep track + // for after so no need to call SetManipulatorAfter + + manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); + manipulatorCommand.release(); } + + EnumerateEditorEntities( + [this](AZ::EntityId entityId) + { + if (IsSelectableInViewport(entityId)) + { + AddEntityToSelection(entityId); + } + }); + + auto nextEntityIds = EntityIdVectorFromContainer(m_selectedEntityIds); + + auto selectionCommand = AZStd::make_unique(nextEntityIds, s_selectAllEntitiesUndoRedoDesc); + selectionCommand->SetParent(undoBatch.GetUndoBatch()); + selectionCommand.release(); + + SetSelectedEntities(nextEntityIds); + RegenerateManipulators(); }); - auto nextEntityIds = EntityIdVectorFromContainer(m_selectedEntityIds); - - auto selectionCommand = AZStd::make_unique( - nextEntityIds, s_selectAllEntitiesUndoRedoDesc); - selectionCommand->SetParent(undoBatch.GetUndoBatch()); - selectionCommand.release(); - - SetSelectedEntities(nextEntityIds); - RegenerateManipulators(); - }); - // invert current selection - AddAction(m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I) }, - /*ID_EDIT_INVERTSELECTION =*/ 33692, - s_invertSelectionTitle, s_invertSelectionDesc, + AddAction( + m_actions, { QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I) }, + /*ID_EDIT_INVERTSELECTION =*/33692, s_invertSelectionTitle, s_invertSelectionDesc, [this]() - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - - ScopedUndoBatch undoBatch(s_invertSelectionUndoRedoDesc); - - if (m_entityIdManipulators.m_manipulators) { - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - // note, nothing will change that the manipulatorCommand needs to keep track - // for after so no need to call SetManipulatorAfter + ScopedUndoBatch undoBatch(s_invertSelectionUndoRedoDesc); - manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); - manipulatorCommand.release(); - } - - EntityIdSet entityIds; - EnumerateEditorEntities([this, &entityIds](AZ::EntityId entityId) - { - const auto entityIdIt = AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), entityId); - if (entityIdIt == m_selectedEntityIds.end()) + if (m_entityIdManipulators.m_manipulators) { - if (IsSelectableInViewport(entityId)) - { - entityIds.insert(entityId); - } + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + + // note, nothing will change that the manipulatorCommand needs to keep track + // for after so no need to call SetManipulatorAfter + + manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); + manipulatorCommand.release(); } + + EntityIdSet entityIds; + EnumerateEditorEntities( + [this, &entityIds](AZ::EntityId entityId) + { + const auto entityIdIt = AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), entityId); + if (entityIdIt == m_selectedEntityIds.end()) + { + if (IsSelectableInViewport(entityId)) + { + entityIds.insert(entityId); + } + } + }); + + m_selectedEntityIds = entityIds; + + auto nextEntityIds = EntityIdVectorFromContainer(entityIds); + + auto selectionCommand = AZStd::make_unique(nextEntityIds, s_invertSelectionUndoRedoDesc); + selectionCommand->SetParent(undoBatch.GetUndoBatch()); + selectionCommand.release(); + + SetSelectedEntities(nextEntityIds); + RegenerateManipulators(); }); - m_selectedEntityIds = entityIds; - - auto nextEntityIds = EntityIdVectorFromContainer(entityIds); - - auto selectionCommand = AZStd::make_unique(nextEntityIds, s_invertSelectionUndoRedoDesc); - selectionCommand->SetParent(undoBatch.GetUndoBatch()); - selectionCommand.release(); - - SetSelectedEntities(nextEntityIds); - RegenerateManipulators(); - }); - bool isPrefabSystemEnabled = false; AzFramework::ApplicationRequests::Bus::BroadcastResult( isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); @@ -2340,8 +2252,10 @@ namespace AzToolsFramework { // duplicate selection AddAction( - m_actions, {QKeySequence(Qt::CTRL + Qt::Key_D)}, - /*ID_EDIT_CLONE =*/33525, s_duplicateTitle, s_duplicateDesc, []() { + m_actions, { QKeySequence(Qt::CTRL + Qt::Key_D) }, + /*ID_EDIT_CLONE =*/33525, s_duplicateTitle, s_duplicateDesc, + []() + { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); // Clear Widget selection - Prevents issues caused by cloning entities while a property in the Reflected Property Editor @@ -2366,121 +2280,113 @@ namespace AzToolsFramework // delete selection AddAction( m_actions, { QKeySequence(Qt::Key_Delete) }, - /*ID_EDIT_DELETE=*/ 33480, - s_deleteTitle, s_deleteDesc, + /*ID_EDIT_DELETE=*/33480, s_deleteTitle, s_deleteDesc, [this]() - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + { + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - ScopedUndoBatch undoBatch(s_deleteUndoRedoDesc); + ScopedUndoBatch undoBatch(s_deleteUndoRedoDesc); - CreateEntityManipulatorDeselectCommand(undoBatch); + CreateEntityManipulatorDeselectCommand(undoBatch); - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::DeleteEntitiesAndAllDescendants, - EntityIdVectorFromContainer(m_selectedEntityIds)); + ToolsApplicationRequestBus::Broadcast( + &ToolsApplicationRequests::DeleteEntitiesAndAllDescendants, EntityIdVectorFromContainer(m_selectedEntityIds)); - m_selectedEntityIds.clear(); - m_pivotOverrideFrame.Reset(); - }); + m_selectedEntityIds.clear(); + m_pivotOverrideFrame.Reset(); + }); AddAction( m_actions, { QKeySequence(Qt::Key_Space) }, - /*ID_EDIT_ESCAPE=*/ 33513, - "", "", + /*ID_EDIT_ESCAPE=*/33513, "", "", [this]() - { - DeselectEntities(); - }); + { + DeselectEntities(); + }); AddAction( m_actions, { QKeySequence(Qt::Key_P) }, - /*ID_EDIT_PIVOT=*/ 36203, - s_togglePivotTitleEditMenu, s_togglePivotDesc, + /*ID_EDIT_PIVOT=*/36203, s_togglePivotTitleEditMenu, s_togglePivotDesc, [this]() - { - ToggleCenterPivotSelection(); - }); + { + ToggleCenterPivotSelection(); + }); AddAction( m_actions, { QKeySequence(Qt::Key_R) }, - /*ID_EDIT_RESET=*/ 36204, - s_resetEntityTransformTitle, s_resetEntityTransformDesc, + /*ID_EDIT_RESET=*/36204, s_resetEntityTransformTitle, s_resetEntityTransformDesc, [this]() - { - switch (m_mode) { - case Mode::Rotation: - ResetOrientationForSelectedEntitiesLocal(); - break; - case Mode::Scale: - CopyScaleToSelectedEntitiesIndividualLocal(1.0f); - break; - case Mode::Translation: - ResetTranslationForSelectedEntitiesLocal(); - break; - } - }); + switch (m_mode) + { + case Mode::Rotation: + ResetOrientationForSelectedEntitiesLocal(); + break; + case Mode::Scale: + CopyScaleToSelectedEntitiesIndividualLocal(1.0f); + break; + case Mode::Translation: + ResetTranslationForSelectedEntitiesLocal(); + break; + } + }); AddAction( m_actions, { QKeySequence(Qt::CTRL + Qt::Key_R) }, - /*ID_EDIT_RESET_MANIPULATOR=*/ 36207, - s_resetManipulatorTitle, s_resetManipulatorDesc, + /*ID_EDIT_RESET_MANIPULATOR=*/36207, s_resetManipulatorTitle, s_resetManipulatorDesc, AZStd::bind(AZStd::mem_fn(&EditorTransformComponentSelection::DelegateClearManipulatorOverride), this)); AddAction( m_actions, { QKeySequence(Qt::ALT + Qt::Key_R) }, - /*ID_EDIT_RESET_LOCAL=*/ 36205, - s_resetTransformLocalTitle, s_resetTransformLocalDesc, + /*ID_EDIT_RESET_LOCAL=*/36205, s_resetTransformLocalTitle, s_resetTransformLocalDesc, [this]() - { - switch (m_mode) { - case Mode::Rotation: - ResetOrientationForSelectedEntitiesLocal(); - break; - case Mode::Scale: - CopyScaleToSelectedEntitiesIndividualWorld(1.0f); - break; - case Mode::Translation: - // do nothing - break; - } - }); + switch (m_mode) + { + case Mode::Rotation: + ResetOrientationForSelectedEntitiesLocal(); + break; + case Mode::Scale: + CopyScaleToSelectedEntitiesIndividualWorld(1.0f); + break; + case Mode::Translation: + // do nothing + break; + } + }); AddAction( m_actions, { QKeySequence(Qt::SHIFT + Qt::Key_R) }, - /*ID_EDIT_RESET_WORLD=*/ 36206, - s_resetTransformWorldTitle, s_resetTransformWorldDesc, + /*ID_EDIT_RESET_WORLD=*/36206, s_resetTransformWorldTitle, s_resetTransformWorldDesc, [this]() - { - switch (m_mode) { - case Mode::Rotation: + switch (m_mode) { - // begin an undo batch so operations inside CopyOrientation... and - // DelegateClear... are grouped into a single undo/redo - ScopedUndoBatch undoBatch { s_resetTransformWorldTitle }; - CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity()); - ClearManipulatorOrientationOverride(); + case Mode::Rotation: + { + // begin an undo batch so operations inside CopyOrientation... and + // DelegateClear... are grouped into a single undo/redo + ScopedUndoBatch undoBatch{ s_resetTransformWorldTitle }; + CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity()); + ClearManipulatorOrientationOverride(); + } + break; + case Mode::Scale: + case Mode::Translation: + break; } - break; - case Mode::Scale: - case Mode::Translation: - break; - } - }); - + }); + AddAction( m_actions, { QKeySequence(Qt::Key_U) }, /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle ViewportUI", "Hide/Unhide Viewport UI", - [this]() - { + [this]() + { SetViewportUiClusterVisible(m_transformModeClusterId, !m_viewportUiVisible); SetViewportUiClusterVisible(m_spaceCluster.m_spaceClusterId, !m_viewportUiVisible); m_viewportUiVisible = !m_viewportUiVisible; - }); - + }); + EditorMenuRequestBus::Broadcast(&EditorMenuRequests::RestoreEditMenuToDefault); } @@ -2488,8 +2394,7 @@ namespace AzToolsFramework { for (auto& action : m_actions) { - EditorActionRequestBus::Broadcast( - &EditorActionRequests::RemoveActionViaBus, action.get()); + EditorActionRequestBus::Broadcast(&EditorActionRequests::RemoveActionViaBus, action.get()); } m_actions.clear(); @@ -2558,42 +2463,37 @@ namespace AzToolsFramework { // create the cluster for changing transform mode ViewportUi::ViewportUiRequestBus::EventResult( - m_transformModeClusterId, ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::CreateCluster, ViewportUi::Alignment::TopLeft); + m_transformModeClusterId, ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + ViewportUi::Alignment::TopLeft); // create and register the buttons (strings correspond to icons even if the values appear different) m_translateButtonId = RegisterClusterButton(m_transformModeClusterId, "Move"); m_rotateButtonId = RegisterClusterButton(m_transformModeClusterId, "Translate"); m_scaleButtonId = RegisterClusterButton(m_transformModeClusterId, "Scale"); - auto onButtonClicked = - [this](ViewportUi::ButtonId buttonId) + auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) + { + if (buttonId == m_translateButtonId) { - if (buttonId == m_translateButtonId) - { - SetTransformMode(Mode::Translation); - } - else if (buttonId == m_rotateButtonId) - { - SetTransformMode(Mode::Rotation); - } - else if (buttonId == m_scaleButtonId) - { - SetTransformMode(Mode::Scale); - } - }; + SetTransformMode(Mode::Translation); + } + else if (buttonId == m_rotateButtonId) + { + SetTransformMode(Mode::Rotation); + } + else if (buttonId == m_scaleButtonId) + { + SetTransformMode(Mode::Scale); + } + }; m_transformModeSelectionHandler = AZ::Event::Handler(onButtonClicked); ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, - m_transformModeClusterId, + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::SetClusterActiveButton, m_transformModeClusterId, m_translateButtonId); ViewportUi::ViewportUiRequestBus::Event( - ViewportUi::DefaultViewportId, - &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, - m_transformModeClusterId, + ViewportUi::DefaultViewportId, &ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_transformModeClusterId, m_transformModeSelectionHandler); } @@ -2609,7 +2509,8 @@ namespace AzToolsFramework m_spaceCluster.m_parentButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Parent"); m_spaceCluster.m_localButtonId = RegisterClusterButton(m_spaceCluster.m_spaceClusterId, "Local"); - auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) { + auto onButtonClicked = [this](ViewportUi::ButtonId buttonId) + { if (buttonId == m_spaceCluster.m_localButtonId) { // Unlock @@ -2674,14 +2575,13 @@ namespace AzToolsFramework if (m_pivotOverrideFrame.m_orientationOverride && m_entityIdManipulators.m_manipulators) { - m_pivotOverrideFrame.m_orientationOverride = QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()); + m_pivotOverrideFrame.m_orientationOverride = + QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()); } if (m_pivotOverrideFrame.m_translationOverride && m_entityIdManipulators.m_manipulators) { - m_pivotOverrideFrame.m_translationOverride = - m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + m_pivotOverrideFrame.m_translationOverride = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); } m_mode = mode; @@ -2758,8 +2658,7 @@ namespace AzToolsFramework // we are responsible for updating the current selection m_didSetSelectedEntities = true; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); } void EditorTransformComponentSelection::RefreshManipulators(const RefreshType refreshType) @@ -2779,15 +2678,13 @@ namespace AzToolsFramework break; case RefreshType::Orientation: transform = AZ::Transform::CreateFromQuaternionAndTranslation( - RecalculateAverageManipulatorOrientation( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_referenceFrame), + RecalculateAverageManipulatorOrientation(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_referenceFrame), m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()); break; case RefreshType::Translation: transform = AZ::Transform::CreateFromQuaternionAndTranslation( m_entityIdManipulators.m_manipulators->GetLocalTransform().GetRotation(), - RecalculateAverageManipulatorTranslation( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode)); + RecalculateAverageManipulatorTranslation(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode)); break; } @@ -2810,9 +2707,8 @@ namespace AzToolsFramework if (m_entityIdManipulators.m_manipulators) { - m_entityIdManipulators.m_manipulators->SetLocalTransform( - AZ::Transform::CreateFromQuaternionAndTranslation( - orientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); + m_entityIdManipulators.m_manipulators->SetLocalTransform(AZ::Transform::CreateFromQuaternionAndTranslation( + orientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); m_entityIdManipulators.m_manipulators->SetBoundsDirty(); } @@ -2839,15 +2735,14 @@ namespace AzToolsFramework { ScopedUndoBatch undoBatch(s_resetManipulatorTranslationUndoRedoDesc); - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); m_pivotOverrideFrame.ResetPickedTranslation(); m_pivotOverrideFrame.m_pickedEntityIdOverride.SetInvalid(); - m_entityIdManipulators.m_manipulators->SetLocalTransform( - RecalculateAverageManipulatorTransform( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); + m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform( + m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame)); m_entityIdManipulators.m_manipulators->SetBoundsDirty(); @@ -2864,20 +2759,18 @@ namespace AzToolsFramework if (m_entityIdManipulators.m_manipulators) { - ScopedUndoBatch undoBatch { s_resetManipulatorOrientationUndoRedoDesc }; + ScopedUndoBatch undoBatch{ s_resetManipulatorOrientationUndoRedoDesc }; - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); m_pivotOverrideFrame.ResetPickedOrientation(); m_pivotOverrideFrame.m_pickedEntityIdOverride.SetInvalid(); // parent reference frame is the default (when no modifiers are held) - m_entityIdManipulators.m_manipulators->SetLocalTransform( - AZ::Transform::CreateFromQuaternionAndTranslation( - ETCS::CalculatePivotOrientationForEntityIds( - m_entityIdManipulators.m_lookups, ReferenceFrame::Parent).m_worldOrientation, - m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); + m_entityIdManipulators.m_manipulators->SetLocalTransform(AZ::Transform::CreateFromQuaternionAndTranslation( + ETCS::CalculatePivotOrientationForEntityIds(m_entityIdManipulators.m_lookups, ReferenceFrame::Parent).m_worldOrientation, + m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation())); m_entityIdManipulators.m_manipulators->SetBoundsDirty(); @@ -2900,8 +2793,7 @@ namespace AzToolsFramework { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - static_assert(AZStd::is_same::value, - "Container key type is not an EntityId"); + static_assert(AZStd::is_same::value, "Container key type is not an EntityId"); AZ::EntityId parentId; AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId); @@ -2935,11 +2827,10 @@ namespace AzToolsFramework ScopedUndoBatch undoBatch(s_dittoTranslationGroupUndoRedoDesc); // store previous translation manipulator position - const AZ::Vector3 previousPivotTranslation = - m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + const AZ::Vector3 previousPivotTranslation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); // refresh the transform pivot override if it's set if (m_pivotOverrideFrame.m_translationOverride) @@ -2947,15 +2838,11 @@ namespace AzToolsFramework OverrideManipulatorTranslation(translation); } - manipulatorCommand->SetManipulatorAfter( - EntityManipulatorCommand::State( - BuildPivotOverride( - m_pivotOverrideFrame.HasTranslationOverride(), - m_pivotOverrideFrame.HasOrientationOverride()), - AZ::Transform::CreateFromQuaternionAndTranslation( - QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()), translation), - m_pivotOverrideFrame.m_pickedEntityIdOverride)); + manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State( + BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()), + AZ::Transform::CreateFromQuaternionAndTranslation( + QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()), translation), + m_pivotOverrideFrame.m_pickedEntityIdOverride)); manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); manipulatorCommand.release(); @@ -2995,8 +2882,8 @@ namespace AzToolsFramework { ScopedUndoBatch undoBatch(s_dittoTranslationIndividualUndoRedoDesc); - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); // refresh the transform pivot override if it's set if (m_pivotOverrideFrame.m_translationOverride) @@ -3004,15 +2891,11 @@ namespace AzToolsFramework OverrideManipulatorTranslation(translation); } - manipulatorCommand->SetManipulatorAfter( - EntityManipulatorCommand::State( - BuildPivotOverride( - m_pivotOverrideFrame.HasTranslationOverride(), - m_pivotOverrideFrame.HasOrientationOverride()), - AZ::Transform::CreateFromQuaternionAndTranslation( - QuaternionFromTransformNoScaling( - m_entityIdManipulators.m_manipulators->GetLocalTransform()), translation), - m_pivotOverrideFrame.m_pickedEntityIdOverride)); + manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State( + BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()), + AZ::Transform::CreateFromQuaternionAndTranslation( + QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform()), translation), + m_pivotOverrideFrame.m_pickedEntityIdOverride)); manipulatorCommand->SetParent(undoBatch.GetUndoBatch()); manipulatorCommand.release(); @@ -3084,17 +2967,16 @@ namespace AzToolsFramework RefreshUiAfterChange(manipulatorEntityIds.m_entityIds); } - void EditorTransformComponentSelection::CopyOrientationToSelectedEntitiesIndividual( - const AZ::Quaternion& orientation) + void EditorTransformComponentSelection::CopyOrientationToSelectedEntitiesIndividual(const AZ::Quaternion& orientation) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); if (m_entityIdManipulators.m_manipulators) { - ScopedUndoBatch undoBatch { s_dittoEntityOrientationIndividualUndoRedoDesc }; + ScopedUndoBatch undoBatch{ s_dittoEntityOrientationIndividualUndoRedoDesc }; - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); ManipulatorEntityIds manipulatorEntityIds; BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds.m_entityIds); @@ -3130,8 +3012,7 @@ namespace AzToolsFramework } } - void EditorTransformComponentSelection::CopyOrientationToSelectedEntitiesGroup( - const AZ::Quaternion& orientation) + void EditorTransformComponentSelection::CopyOrientationToSelectedEntitiesGroup(const AZ::Quaternion& orientation) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -3139,8 +3020,8 @@ namespace AzToolsFramework { ScopedUndoBatch undoBatch(s_dittoEntityOrientationGroupUndoRedoDesc); - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); ManipulatorEntityIds manipulatorEntityIds; BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds.m_entityIds); @@ -3148,8 +3029,7 @@ namespace AzToolsFramework // save initial transforms const auto transformsBefore = RecordTransformsBefore(manipulatorEntityIds.m_entityIds); - const AZ::Transform currentTransform = - m_entityIdManipulators.m_manipulators->GetLocalTransform(); + const AZ::Transform currentTransform = m_entityIdManipulators.m_manipulators->GetLocalTransform(); const AZ::Transform nextTransform = AZ::Transform::CreateFromQuaternionAndTranslation( orientation, m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation()); @@ -3163,8 +3043,7 @@ namespace AzToolsFramework const auto transformIt = transformsBefore.find(entityId); if (transformIt != transformsBefore.end()) { - const AZ::Transform transformInPivotSpace = - currentTransform.GetInverse() * transformIt->second; + const AZ::Transform transformInPivotSpace = currentTransform.GetInverse() * transformIt->second; SetEntityWorldTransform(entityId, nextTransform * transformInPivotSpace); } @@ -3186,7 +3065,7 @@ namespace AzToolsFramework AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); ScopedUndoBatch undoBatch(s_resetOrientationToParentUndoRedoDesc); - for (const auto& entityIdLookup: m_entityIdManipulators.m_lookups) + for (const auto& entityIdLookup : m_entityIdManipulators.m_lookups) { ScopedUndoBatch::MarkEntityDirty(entityIdLookup.first); SetEntityLocalRotation(entityIdLookup.first, AZ::Vector3::CreateZero()); @@ -3209,14 +3088,12 @@ namespace AzToolsFramework ScopedUndoBatch undoBatch(s_resetTranslationToParentUndoRedoDesc); ManipulatorEntityIds manipulatorEntityIds; - BuildSortedEntityIdVectorFromEntityIdMap( - m_entityIdManipulators.m_lookups, manipulatorEntityIds.m_entityIds); + BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds.m_entityIds); for (AZ::EntityId entityId : manipulatorEntityIds.m_entityIds) { AZ::EntityId parentId; - AZ::TransformBus::EventResult( - parentId, entityId, &AZ::TransformBus::Events::GetParentId); + AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId); if (parentId.IsValid()) { @@ -3231,11 +3108,15 @@ namespace AzToolsFramework } } - void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu( - QMenu* menu, const AZ::Vector2& /*point*/, const int /*flags*/) + void EditorTransformComponentSelection::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& /*point*/, const int /*flags*/) { QAction* action = menu->addAction(QObject::tr(s_togglePivotTitleRightClick)); - QObject::connect(action, &QAction::triggered, action, [this]() { ToggleCenterPivotSelection(); }); + QObject::connect( + action, &QAction::triggered, action, + [this]() + { + ToggleCenterPivotSelection(); + }); } void EditorTransformComponentSelection::BeforeEntitySelectionChanged() @@ -3281,8 +3162,10 @@ namespace AzToolsFramework } static void DrawPreviewAxis( - AzFramework::DebugDisplayRequests& display, const AZ::Transform& transform, - const float axisLength, const AzFramework::CameraState& cameraState) + AzFramework::DebugDisplayRequests& display, + const AZ::Transform& transform, + const float axisLength, + const AzFramework::CameraState& cameraState) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -3297,8 +3180,8 @@ namespace AzToolsFramework const auto axisFlip = [&transform, &cameraState](const AZ::Vector3& axis) -> float { return ShouldFlipCameraAxis( - AZ::Transform::CreateIdentity(), transform.GetTranslation(), - TransformDirectionNoScaling(transform, axis), cameraState) + AZ::Transform::CreateIdentity(), transform.GetTranslation(), TransformDirectionNoScaling(transform, axis), + cameraState) ? -1.0f : 1.0f; }; @@ -3306,18 +3189,15 @@ namespace AzToolsFramework display.SetColor(s_fadedXAxisColor); display.DrawLine( transform.GetTranslation(), - transform.GetTranslation() + transform.GetBasisX().GetNormalizedSafe() * - axisLength * axisFlip(AZ::Vector3::CreateAxisX())); + transform.GetTranslation() + transform.GetBasisX().GetNormalizedSafe() * axisLength * axisFlip(AZ::Vector3::CreateAxisX())); display.SetColor(s_fadedYAxisColor); display.DrawLine( transform.GetTranslation(), - transform.GetTranslation() + transform.GetBasisY().GetNormalizedSafe() * - axisLength * axisFlip(AZ::Vector3::CreateAxisY())); + transform.GetTranslation() + transform.GetBasisY().GetNormalizedSafe() * axisLength * axisFlip(AZ::Vector3::CreateAxisY())); display.SetColor(s_fadedZAxisColor); display.DrawLine( transform.GetTranslation(), - transform.GetTranslation() + transform.GetBasisZ().GetNormalizedSafe() * - axisLength * axisFlip(AZ::Vector3::CreateAxisZ())); + transform.GetTranslation() + transform.GetBasisZ().GetNormalizedSafe() * axisLength * axisFlip(AZ::Vector3::CreateAxisZ())); display.DepthWriteOn(); display.DepthTestOn(); @@ -3330,15 +3210,11 @@ namespace AzToolsFramework static void DrawManipulatorGrid( AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, const float gridSize) { - const AZ::Matrix3x3 orientation = - AZ::Matrix3x3::CreateFromTransform(entityIdManipulators.m_manipulators->GetLocalTransform()); + const AZ::Matrix3x3 orientation = AZ::Matrix3x3::CreateFromTransform(entityIdManipulators.m_manipulators->GetLocalTransform()); - const AZ::Vector3 translation = - entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); + const AZ::Vector3 translation = entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation(); - DrawSnappingGrid( - debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, translation), - gridSize); + DrawSnappingGrid(debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, translation), gridSize); } void EditorTransformComponentSelection::DisplayViewportSelection( @@ -3348,16 +3224,14 @@ namespace AzToolsFramework CheckDirtyEntityIds(); - const auto modifiers = ViewportInteraction::KeyboardModifiers( - ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); + const auto modifiers = + ViewportInteraction::KeyboardModifiers(ViewportInteraction::TranslateKeyboardModifiers(QApplication::queryKeyboardModifiers())); m_cursorState.Update(); HandleAccents( - !m_selectedEntityIds.empty(), m_cachedEntityIdUnderCursor, - modifiers.Ctrl(), m_hoveredEntityId, - ViewportInteraction::BuildMouseButtons( - QGuiApplication::mouseButtons()), m_boxSelect.Active()); + !m_selectedEntityIds.empty(), m_cachedEntityIdUnderCursor, modifiers.Ctrl(), m_hoveredEntityId, + ViewportInteraction::BuildMouseButtons(QGuiApplication::mouseButtons()), m_boxSelect.Active()); const ReferenceFrame referenceFrame = m_spaceCluster.m_spaceLock.value_or(ReferenceFrameFromModifiers(modifiers)); @@ -3370,10 +3244,8 @@ namespace AzToolsFramework refresh = true; } - refresh = refresh - || (m_triedToRefresh - && m_entityIdManipulators.m_manipulators - && !m_entityIdManipulators.m_manipulators->PerformingAction()); + refresh = refresh || + (m_triedToRefresh && m_entityIdManipulators.m_manipulators && !m_entityIdManipulators.m_manipulators->PerformingAction()); // we've moved from parent to world space, parent to local space or vice versa by holding or // releasing shift and/or alt - make sure we update the manipulator orientation appropriately @@ -3386,8 +3258,7 @@ namespace AzToolsFramework const auto entityFilter = [this](AZ::EntityId entityId) { - const bool entityHasManipulator = - m_entityIdManipulators.m_lookups.find(entityId) != m_entityIdManipulators.m_lookups.end(); + const bool entityHasManipulator = m_entityIdManipulators.m_lookups.find(entityId) != m_entityIdManipulators.m_lookups.end(); return !entityHasManipulator; }; @@ -3398,15 +3269,12 @@ namespace AzToolsFramework { if (m_pivotOverrideFrame.m_pickedEntityIdOverride.IsValid()) { - const AZ::Transform pickedEntityWorldTransform = - AZ::Transform::CreateFromQuaternionAndTranslation( - ETCS::CalculatePivotOrientation( - m_pivotOverrideFrame.m_pickedEntityIdOverride, referenceFrame).m_worldOrientation, - CalculatePivotTranslation( - m_pivotOverrideFrame.m_pickedEntityIdOverride, m_pivotMode)); + const AZ::Transform pickedEntityWorldTransform = AZ::Transform::CreateFromQuaternionAndTranslation( + ETCS::CalculatePivotOrientation(m_pivotOverrideFrame.m_pickedEntityIdOverride, referenceFrame).m_worldOrientation, + CalculatePivotTranslation(m_pivotOverrideFrame.m_pickedEntityIdOverride, m_pivotMode)); - const float scaledSize = s_pivotSize * - CalculateScreenToWorldMultiplier(pickedEntityWorldTransform.GetTranslation(), cameraState); + const float scaledSize = + s_pivotSize * CalculateScreenToWorldMultiplier(pickedEntityWorldTransform.GetTranslation(), cameraState); debugDisplay.DepthWriteOff(); debugDisplay.DepthTestOff(); @@ -3421,8 +3289,8 @@ namespace AzToolsFramework // check what pivot orientation we are in (based on if a modifier is // held to move us from parent to world space or parent to local space) // or if we set a pivot override - const auto pivotResult = ETCS::CalculateSelectionPivotOrientation( - m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_referenceFrame); + const auto pivotResult = + ETCS::CalculateSelectionPivotOrientation(m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_referenceFrame); // if the reference frame was parent space and the selection does have a // valid parent, draw a preview axis at its position/orientation @@ -3432,8 +3300,7 @@ namespace AzToolsFramework { const AZ::Transform& worldFromLocal = m_entityDataCache->GetVisibleEntityTransform(*parentEntityIndex); - const float adjustedLineLength = - CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); + const float adjustedLineLength = CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); DrawPreviewAxis(debugDisplay, worldFromLocal, adjustedLineLength, cameraState); } @@ -3452,10 +3319,11 @@ namespace AzToolsFramework const AZ::Vector3 boxPosition = worldFromLocal.TransformPoint(CalculateCenterOffset(entityId, m_pivotMode)); - const AZ::Vector3 scaledSize = AZ::Vector3(s_pivotSize) * - CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); + const AZ::Vector3 scaledSize = + AZ::Vector3(s_pivotSize) * CalculateScreenToWorldMultiplier(worldFromLocal.GetTranslation(), cameraState); - const AZ::Color hiddenNormal[] = { AzFramework::ViewportColors::SelectedColor, AzFramework::ViewportColors::HiddenColor }; + const AZ::Color hiddenNormal[] = { AzFramework::ViewportColors::SelectedColor, + AzFramework::ViewportColors::HiddenColor }; AZ::Color boxColor = hiddenNormal[hidden]; const AZ::Color lockedOther[] = { boxColor, AzFramework::ViewportColors::LockColor }; boxColor = lockedOther[locked]; @@ -3470,8 +3338,7 @@ namespace AzToolsFramework debugDisplay.DepthWriteOn(); debugDisplay.DepthTestOn(); - if (ShowingGrid(viewportInfo.m_viewportId) && m_mode == Mode::Translation && - !ComponentModeFramework::InComponentMode()) + if (ShowingGrid(viewportInfo.m_viewportId) && m_mode == Mode::Translation && !ComponentModeFramework::InComponentMode()) { const GridSnapParameters gridSnapParams = GridSnapSettings(viewportInfo.m_viewportId); if (gridSnapParams.m_gridSnap && m_entityIdManipulators.m_manipulators) @@ -3491,11 +3358,11 @@ namespace AzToolsFramework if (m_entityIdManipulators.m_manipulators->PerformingAction()) { - const float adjustedLineLength = 2.0f * - CalculateScreenToWorldMultiplier(m_axisPreview.m_translation, cameraState); + const float adjustedLineLength = 2.0f * CalculateScreenToWorldMultiplier(m_axisPreview.m_translation, cameraState); - DrawPreviewAxis(debugDisplay, AZ::Transform::CreateFromQuaternionAndTranslation( - m_axisPreview.m_orientation, m_axisPreview.m_translation), + DrawPreviewAxis( + debugDisplay, + AZ::Transform::CreateFromQuaternionAndTranslation(m_axisPreview.m_orientation, m_axisPreview.m_translation), adjustedLineLength, cameraState); } } @@ -3503,20 +3370,17 @@ namespace AzToolsFramework m_boxSelect.DisplayScene(viewportInfo, debugDisplay); } - static void DrawAxisGizmo( - const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) + static void DrawAxisGizmo(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { // get the editor cameras current orientation const int viewportId = viewportInfo.m_viewportId; const AzFramework::CameraState editorCameraState = GetCameraState(viewportId); - const AZ::Matrix3x3& editorCameraOrientation = - AZ::Matrix3x3::CreateFromMatrix4x4(AzFramework::CameraTransform(editorCameraState)); + const AZ::Matrix3x3& editorCameraOrientation = AZ::Matrix3x3::CreateFromMatrix4x4(AzFramework::CameraTransform(editorCameraState)); // create a gizmo camera transform about the origin matching the orientation of the editor camera // (10 units back in the y axis to produce an orbit effect) const AZ::Transform gizmoCameraOffset = AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(10.0f)); - const AZ::Transform gizmoCameraTransform = - AZ::Transform::CreateFromMatrix3x3(editorCameraOrientation) * gizmoCameraOffset; + const AZ::Transform gizmoCameraTransform = AZ::Transform::CreateFromMatrix3x3(editorCameraOrientation) * gizmoCameraOffset; const AzFramework::CameraState gizmoCameraState = AzFramework::CreateDefaultCamera(gizmoCameraTransform, editorCameraState.m_viewportSize); @@ -3529,16 +3393,9 @@ namespace AzToolsFramework // map from a position in world space (relative to the the gizmo camera near the origin) to a position in // screen space - const auto calculateGizmoAxis = - [&cameraView, &cameraProjection, &screenOffset] - (const AZ::Vector3& axis) + const auto calculateGizmoAxis = [&cameraView, &cameraProjection, &screenOffset](const AZ::Vector3& axis) { - auto result = AZ::Vector2( - AzFramework::WorldToScreenNDC( - axis, - cameraView, - cameraProjection) - ); + auto result = AZ::Vector2(AzFramework::WorldToScreenNDC(axis, cameraView, cameraProjection)); result.SetY(1.0f - result.GetY()); return result + screenOffset; }; @@ -3552,7 +3409,7 @@ namespace AzToolsFramework const AZ::Vector2 gizmoAxisX = gizmoEndAxisX - gizmoStart; const AZ::Vector2 gizmoAxisY = gizmoEndAxisY - gizmoStart; - const AZ::Vector2 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; + const AZ::Vector2 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; // draw the axes of the gizmo debugDisplay.SetLineWidth(cl_viewportGizmoAxisLineWidth); @@ -3579,8 +3436,7 @@ namespace AzToolsFramework } void EditorTransformComponentSelection::DisplayViewportSelection2d( - const AzFramework::ViewportInfo& viewportInfo, - AzFramework::DebugDisplayRequests& debugDisplay) + const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -3595,8 +3451,7 @@ namespace AzToolsFramework // check what the 'authoritative' selected entity ids are after an undo/redo EntityIdList selectedEntityIds; - ToolsApplicationRequests::Bus::BroadcastResult( - selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities); + ToolsApplicationRequests::Bus::BroadcastResult(selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities); RefreshSelectedEntityIds(selectedEntityIds); } @@ -3614,9 +3469,7 @@ namespace AzToolsFramework // update selected entityId set m_selectedEntityIds.clear(); m_selectedEntityIds.reserve(selectedEntityIds.size()); - AZStd::copy( - selectedEntityIds.begin(), selectedEntityIds.end(), - AZStd::inserter(m_selectedEntityIds, m_selectedEntityIds.end())); + AZStd::copy(selectedEntityIds.begin(), selectedEntityIds.end(), AZStd::inserter(m_selectedEntityIds, m_selectedEntityIds.end())); } void EditorTransformComponentSelection::OnTransformChanged( @@ -3690,8 +3543,7 @@ namespace AzToolsFramework m_selectedEntityIdsAndManipulatorsDirty = true; } - void EditorTransformComponentSelection::EnteredComponentMode( - const AZStd::vector& /*componentModeTypes*/) + void EditorTransformComponentSelection::EnteredComponentMode(const AZStd::vector& /*componentModeTypes*/) { SetViewportUiClusterVisible(m_transformModeClusterId, false); @@ -3700,8 +3552,7 @@ namespace AzToolsFramework ToolsApplicationNotificationBus::Handler::BusDisconnect(); } - void EditorTransformComponentSelection::LeftComponentMode( - const AZStd::vector& /*componentModeTypes*/) + void EditorTransformComponentSelection::LeftComponentMode(const AZStd::vector& /*componentModeTypes*/) { SetViewportUiClusterVisible(m_transformModeClusterId, true); @@ -3714,8 +3565,8 @@ namespace AzToolsFramework { if (m_entityIdManipulators.m_manipulators) { - auto manipulatorCommand = AZStd::make_unique( - CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); + auto manipulatorCommand = + AZStd::make_unique(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName); manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State()); @@ -3734,32 +3585,27 @@ namespace AzToolsFramework return {}; } - void EditorTransformComponentSelection::SetEntityWorldTranslation( - const AZ::EntityId entityId, const AZ::Vector3& worldTranslation) + void EditorTransformComponentSelection::SetEntityWorldTranslation(const AZ::EntityId entityId, const AZ::Vector3& worldTranslation) { ETCS::SetEntityWorldTranslation(entityId, worldTranslation, m_transformChangedInternally); } - void EditorTransformComponentSelection::SetEntityLocalTranslation( - const AZ::EntityId entityId, const AZ::Vector3& localTranslation) + void EditorTransformComponentSelection::SetEntityLocalTranslation(const AZ::EntityId entityId, const AZ::Vector3& localTranslation) { ETCS::SetEntityLocalTranslation(entityId, localTranslation, m_transformChangedInternally); } - void EditorTransformComponentSelection::SetEntityWorldTransform( - const AZ::EntityId entityId, const AZ::Transform& worldTransform) + void EditorTransformComponentSelection::SetEntityWorldTransform(const AZ::EntityId entityId, const AZ::Transform& worldTransform) { ETCS::SetEntityWorldTransform(entityId, worldTransform, m_transformChangedInternally); } - void EditorTransformComponentSelection::SetEntityLocalScale( - const AZ::EntityId entityId, const float localScale) + void EditorTransformComponentSelection::SetEntityLocalScale(const AZ::EntityId entityId, const float localScale) { ETCS::SetEntityLocalScale(entityId, localScale, m_transformChangedInternally); } - void EditorTransformComponentSelection::SetEntityLocalRotation( - const AZ::EntityId entityId, const AZ::Vector3& localRotation) + void EditorTransformComponentSelection::SetEntityLocalRotation(const AZ::EntityId entityId, const AZ::Vector3& localRotation) { ETCS::SetEntityLocalRotation(entityId, localRotation, m_transformChangedInternally); } @@ -3788,44 +3634,37 @@ namespace AzToolsFramework void SetEntityWorldTranslation(AZ::EntityId entityId, const AZ::Vector3& worldTranslation, bool& internal) { ScopeSwitch sw(internal); - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetWorldTranslation, worldTranslation); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTranslation, worldTranslation); } void SetEntityLocalTranslation(AZ::EntityId entityId, const AZ::Vector3& localTranslation, bool& internal) { ScopeSwitch sw(internal); - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetLocalTranslation, localTranslation); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTranslation, localTranslation); } void SetEntityWorldTransform(AZ::EntityId entityId, const AZ::Transform& worldTransform, bool& internal) { ScopeSwitch sw(internal); - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetWorldTM, worldTransform); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, worldTransform); } void SetEntityLocalScale(AZ::EntityId entityId, float localScale, bool& internal) { ScopeSwitch sw(internal); - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetLocalUniformScale, localScale); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, localScale); } void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation, bool& internal) { ScopeSwitch sw(internal); - AZ::TransformBus::Event( - entityId, &AZ::TransformBus::Events::SetLocalRotation, localRotation); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalRotation, localRotation); } } // namespace ETCS // explicit instantiations - template ETCS::PivotOrientationResult - ETCS::CalculatePivotOrientationForEntityIds( - const EntityIdManipulatorLookups&, ReferenceFrame); - template ETCS::PivotOrientationResult - ETCS::CalculateSelectionPivotOrientation( - const EntityIdManipulatorLookups&, const OptionalFrame&, const ReferenceFrame referenceFrame); + template ETCS::PivotOrientationResult ETCS::CalculatePivotOrientationForEntityIds( + const EntityIdManipulatorLookups&, ReferenceFrame); + template ETCS::PivotOrientationResult ETCS::CalculateSelectionPivotOrientation( + const EntityIdManipulatorLookups&, const OptionalFrame&, const ReferenceFrame referenceFrame); } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp index 9ca20068ed..8cd19b8d2d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.cpp @@ -1,17 +1,17 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ -#include #include "EditorTransformComponentSelectionRequestBus.h" +#include namespace AzToolsFramework { @@ -19,50 +19,68 @@ namespace AzToolsFramework { if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - #define TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests() \ - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) \ - ->Attribute(AZ::Script::Attributes::Category, "Editor") \ - ->Attribute(AZ::Script::Attributes::Module, "editor") +#define TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests() \ + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) \ + ->Attribute(AZ::Script::Attributes::Category, "Editor") \ + ->Attribute(AZ::Script::Attributes::Module, "editor") - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Mode::Rotation)>("TransformMode_Rotation") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Mode::Translation)>("TransformMode_Translation") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Mode::Rotation)>( + "TransformMode_Rotation") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Mode::Translation)>( + "TransformMode_Translation") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Mode::Scale)>("TransformMode_Scale") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::Translation)>("TransformRefreshType_Translation") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::Orientation)>("TransformRefreshType_Orientation") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::All)>("TransformRefreshType_All") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::Translation)>( + "TransformRefreshType_Translation") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::Orientation)>( + "TransformRefreshType_Orientation") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::RefreshType::All)>( + "TransformRefreshType_All") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Pivot::Object)>("TransformPivot_Object") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Pivot::Center)>("TransformPivot_Center") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Pivot::Object)>( + "TransformPivot_Object") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); + behaviorContext->EnumProperty(EditorTransformComponentSelectionRequests::Pivot::Center)>( + "TransformPivot_Center") TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests(); - behaviorContext->EBus("EditorTransformComponentSelectionRequestBus") - TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests() + behaviorContext + ->EBus("EditorTransformComponentSelectionRequestBus") + TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests() ->Event("SetTransformMode", &EditorTransformComponentSelectionRequestBus::Events::SetTransformMode) ->Event("GetTransformMode", &EditorTransformComponentSelectionRequestBus::Events::GetTransformMode) // Reflecting GetManipulatorTransform will require hash to be implemented, a pending task. //->Event("GetManipulatorTransform", &EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform) ->Event("RefreshManipulators", &EditorTransformComponentSelectionRequestBus::Events::RefreshManipulators) - ->Event("OverrideManipulatorOrientation", &EditorTransformComponentSelectionRequestBus::Events::OverrideManipulatorOrientation) - ->Event("OverrideManipulatorTranslation", &EditorTransformComponentSelectionRequestBus::Events::OverrideManipulatorTranslation) - ->Event("CopyTranslationToSelectedEntitiesIndividual", &EditorTransformComponentSelectionRequestBus::Events::CopyTranslationToSelectedEntitiesIndividual) - ->Event("CopyTranslationToSelectedEntitiesGroup", &EditorTransformComponentSelectionRequestBus::Events::CopyTranslationToSelectedEntitiesGroup) - ->Event("ResetTranslationForSelectedEntitiesLocal", &EditorTransformComponentSelectionRequestBus::Events::ResetTranslationForSelectedEntitiesLocal) - ->Event("CopyOrientationToSelectedEntitiesIndividual", &EditorTransformComponentSelectionRequestBus::Events::CopyOrientationToSelectedEntitiesIndividual) - ->Event("CopyOrientationToSelectedEntitiesGroup", &EditorTransformComponentSelectionRequestBus::Events::CopyOrientationToSelectedEntitiesGroup) - ->Event("ResetOrientationForSelectedEntitiesLocal", &EditorTransformComponentSelectionRequestBus::Events::ResetOrientationForSelectedEntitiesLocal) - ->Event("CopyScaleToSelectedEntitiesIndividualLocal", &EditorTransformComponentSelectionRequestBus::Events::CopyScaleToSelectedEntitiesIndividualLocal) - ->Event("CopyScaleToSelectedEntitiesIndividualWorld", &EditorTransformComponentSelectionRequestBus::Events::CopyScaleToSelectedEntitiesIndividualWorld) - ; + ->Event( + "OverrideManipulatorOrientation", &EditorTransformComponentSelectionRequestBus::Events::OverrideManipulatorOrientation) + ->Event( + "OverrideManipulatorTranslation", &EditorTransformComponentSelectionRequestBus::Events::OverrideManipulatorTranslation) + ->Event( + "CopyTranslationToSelectedEntitiesIndividual", + &EditorTransformComponentSelectionRequestBus::Events::CopyTranslationToSelectedEntitiesIndividual) + ->Event( + "CopyTranslationToSelectedEntitiesGroup", + &EditorTransformComponentSelectionRequestBus::Events::CopyTranslationToSelectedEntitiesGroup) + ->Event( + "ResetTranslationForSelectedEntitiesLocal", + &EditorTransformComponentSelectionRequestBus::Events::ResetTranslationForSelectedEntitiesLocal) + ->Event( + "CopyOrientationToSelectedEntitiesIndividual", + &EditorTransformComponentSelectionRequestBus::Events::CopyOrientationToSelectedEntitiesIndividual) + ->Event( + "CopyOrientationToSelectedEntitiesGroup", + &EditorTransformComponentSelectionRequestBus::Events::CopyOrientationToSelectedEntitiesGroup) + ->Event( + "ResetOrientationForSelectedEntitiesLocal", + &EditorTransformComponentSelectionRequestBus::Events::ResetOrientationForSelectedEntitiesLocal) + ->Event( + "CopyScaleToSelectedEntitiesIndividualLocal", + &EditorTransformComponentSelectionRequestBus::Events::CopyScaleToSelectedEntitiesIndividualLocal) + ->Event( + "CopyScaleToSelectedEntitiesIndividualWorld", + &EditorTransformComponentSelectionRequestBus::Events::CopyScaleToSelectedEntitiesIndividualWorld); - #undef TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests +#undef TEMP_SET_ATTRIBUTES_FOR_EditorTransformComponentSelectionRequests } } } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h index 9cd78f8c50..966f9333fc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -16,12 +16,10 @@ #include #include - namespace AzToolsFramework { - /// Provide interface for EditorTransformComponentSelection requests. - class EditorTransformComponentSelectionRequests - : public AZ::EBusTraits + //! Provide interface for EditorTransformComponentSelection requests. + class EditorTransformComponentSelectionRequests : public AZ::EBusTraits { public: using BusIdType = AzFramework::EntityContextId; @@ -30,7 +28,7 @@ namespace AzToolsFramework static void Reflect(AZ::ReflectContext* context); - /// What type of transform editing are we in. + //! What type of transform editing are we in. enum class Mode { // note: ordering of these is important - do not change. @@ -40,7 +38,7 @@ namespace AzToolsFramework Scale }; - /// Specify the type of refresh (what type of transform modification caused the refresh). + //! Specify the type of refresh (what type of transform modification caused the refresh). enum class RefreshType { Translation, @@ -48,69 +46,69 @@ namespace AzToolsFramework All }; - /// How is the pivot aligned (object/authored position or center). + //! How is the pivot aligned (object/authored position or center). enum class Pivot { Object, Center }; - /// Set what kind of transform the type that implements this bus should use. + //! Set what kind of transform the type that implements this bus should use. virtual void SetTransformMode(Mode mode) = 0; - /// Return what transform mode the type that implements this bus is using. + //! Return what transform mode the type that implements this bus is using. virtual Mode GetTransformMode() = 0; - /// Return the current Entity Manipulator transform. - /// An AZStd::optional is returned as if we do not have a selection - /// there will be no Manipulator present. In this case we return an empty optional. + //! Return the current Entity Manipulator transform. + //! An AZStd::optional is returned as if we do not have a selection + //! there will be no Manipulator present. In this case we return an empty optional. virtual AZStd::optional GetManipulatorTransform() = 0; - /// Refresh the Manipulator based on the current entity selection. - /// This may be useful if the Entity transform has been set outside - /// of the EditorTransformComponentSelection and we want to make sure the - /// Manipulator stays up to date (in sync) with the current Entity transform. + //! Refresh the Manipulator based on the current entity selection. + //! This may be useful if the Entity transform has been set outside + //! of the EditorTransformComponentSelection and we want to make sure the + //! Manipulator stays up to date (in sync) with the current Entity transform. virtual void RefreshManipulators(RefreshType refreshType) = 0; - /// Set an orientation override for the Manipulator. - /// Useful if we've picked another Entity transform to use as our reference point. + //! Set an orientation override for the Manipulator. + //! Useful if we've picked another Entity transform to use as our reference point. virtual void OverrideManipulatorOrientation(const AZ::Quaternion& orientation) = 0; - /// Set a translation override for the Manipulator. - /// Useful if we've picked another Entity transform to use as our reference point. + //! Set a translation override for the Manipulator. + //! Useful if we've picked another Entity transform to use as our reference point. virtual void OverrideManipulatorTranslation(const AZ::Vector3& translation) = 0; - /// Copy translation to each individual entity so they all appear in the exact same position. + //! Copy translation to each individual entity so they all appear in the exact same position. virtual void CopyTranslationToSelectedEntitiesIndividual(const AZ::Vector3& translation) = 0; - /// Copy translation to manipulator position with each entity keeping the same relative position as before. + //! Copy translation to manipulator position with each entity keeping the same relative position as before. virtual void CopyTranslationToSelectedEntitiesGroup(const AZ::Vector3& translation) = 0; - /// Reset the translation of an entity to the same position as its parent. - /// Note: This is a noop if the entity does not have a parent. + //! Reset the translation of an entity to the same position as its parent. + //! Note: This is a noop if the entity does not have a parent. virtual void ResetTranslationForSelectedEntitiesLocal() = 0; - /// Copy orientation to each individual entity so they all appear in the exact same orientation. + //! Copy orientation to each individual entity so they all appear in the exact same orientation. virtual void CopyOrientationToSelectedEntitiesIndividual(const AZ::Quaternion& orientation) = 0; - /// Copy orientation to manipulator with each entity keeping the same relative orientation as before. + //! Copy orientation to manipulator with each entity keeping the same relative orientation as before. virtual void CopyOrientationToSelectedEntitiesGroup(const AZ::Quaternion& orientation) = 0; - /// Reset the orientation of an entity to the same orientation as its parent. - /// Note: This will be the aligned to the world axes (identity) if the entity does not have a parent. + //! Reset the orientation of an entity to the same orientation as its parent. + //! Note: This will be the aligned to the world axes (identity) if the entity does not have a parent. virtual void ResetOrientationForSelectedEntitiesLocal() = 0; - /// Copy scale to each individual entity in local space without moving position. + //! Copy scale to each individual entity in local space without moving position. virtual void CopyScaleToSelectedEntitiesIndividualLocal(float scale) = 0; - /// Copy scale to to each individual entity in world (absolute) space. + //! Copy scale to to each individual entity in world (absolute) space. virtual void CopyScaleToSelectedEntitiesIndividualWorld(float scale) = 0; protected: ~EditorTransformComponentSelectionRequests() = default; }; - /// Type to inherit to implement EditorTransformComponentSelectionRequests. + //! Type to inherit to implement EditorTransformComponentSelectionRequests. using EditorTransformComponentSelectionRequestBus = AZ::EBus; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp index 253c27fe02..0e066684d2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.cpp @@ -1,33 +1,31 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "EditorVisibleEntityDataCache.h" #include +#include #include #include -#include namespace AzToolsFramework { - /// Cached Entity data required by the selection. + //! Cached Entity data required by the selection. struct EntityData final { using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType; EntityData() = default; - EntityData( - AZ::EntityId entityId, const AZ::Transform& worldFromLocal, - bool locked, bool visible, bool selected, bool iconHidden); + EntityData(AZ::EntityId entityId, const AZ::Transform& worldFromLocal, bool locked, bool visible, bool selected, bool iconHidden); AZ::Transform m_worldFromLocal; AZ::EntityId m_entityId; @@ -38,7 +36,7 @@ namespace AzToolsFramework bool m_iconHidden = false; }; - using EntityDatas = AZStd::vector; ///< Alias for vector of EntityDatas. + using EntityDatas = AZStd::vector; //!< Alias for vector of EntityDatas. // Predicate to sort EntityIds with EntityDatas interchangeably. struct EntityDataComparer @@ -52,18 +50,27 @@ namespace AzToolsFramework class EditorVisibleEntityDataCache::EditorVisibleEntityDataCacheImpl { public: - EntityIdList m_visibleEntityIds; ///< The EntityIds that are visible this frame. - EntityIdList m_prevVisibleEntityIds; ///< The EntityIds that were visible the previous frame (unsorted). - EntityDatas m_visibleEntityDatas; ///< Cached EntityData required by EditorTransformComponentSelection. + EntityIdList m_visibleEntityIds; //!< The EntityIds that are visible this frame. + EntityIdList m_prevVisibleEntityIds; //!< The EntityIds that were visible the previous frame (unsorted). + EntityDatas m_visibleEntityDatas; //!< Cached EntityData required by EditorTransformComponentSelection. }; // constructor for EntityData to support emplace_back in vector EntityData::EntityData( - const AZ::EntityId entityId, const AZ::Transform& worldFromLocal, - const bool locked, const bool visible, const bool selected, const bool iconHidden) - : m_worldFromLocal(worldFromLocal), m_entityId(entityId) - , m_locked(locked), m_visible(visible), m_selected(selected) - , m_iconHidden(iconHidden) {} + const AZ::EntityId entityId, + const AZ::Transform& worldFromLocal, + const bool locked, + const bool visible, + const bool selected, + const bool iconHidden) + : m_worldFromLocal(worldFromLocal) + , m_entityId(entityId) + , m_locked(locked) + , m_visible(visible) + , m_selected(selected) + , m_iconHidden(iconHidden) + { + } bool EntityDataComparer::operator()(const AZ::EntityId lhs, const EntityData& rhs) const { @@ -98,20 +105,17 @@ namespace AzToolsFramework static EntityData EntityDataFromEntityId(const AZ::EntityId entityId) { bool visible = false; - EditorEntityInfoRequestBus::EventResult( - visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible); + EditorEntityInfoRequestBus::EventResult(visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible); bool locked = false; - EditorEntityInfoRequestBus::EventResult( - locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked); + EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked); bool iconHidden = false; EditorEntityIconComponentRequestBus::EventResult( iconHidden, entityId, &EditorEntityIconComponentRequests::IsEntityIconHiddenInViewport); AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); + AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM); return { entityId, worldFromLocal, locked, visible, IsSelected(entityId), iconHidden }; } @@ -155,16 +159,14 @@ namespace AzToolsFramework AZStd::sort(m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end()); } - void EditorVisibleEntityDataCache::CalculateVisibleEntityDatas( - const AzFramework::ViewportInfo& viewportInfo) + void EditorVisibleEntityDataCache::CalculateVisibleEntityDatas(const AzFramework::ViewportInfo& viewportInfo) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); // request list of visible entities from authoritative system EntityIdList nextVisibleEntityIds; ViewportInteraction::MainEditorViewportInteractionRequestBus::Event( - viewportInfo.m_viewportId, - &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::FindVisibleEntities, + viewportInfo.m_viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::FindVisibleEntities, nextVisibleEntityIds); // only bother resorting if we know the lists have changed @@ -181,31 +183,26 @@ namespace AzToolsFramework // find entities that are visible this frame but weren't last frame AZStd::vector added; std::set_difference( - m_impl->m_visibleEntityIds.begin(), m_impl->m_visibleEntityIds.end(), - m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), - std::back_inserter(added), EntityDataComparer()); + m_impl->m_visibleEntityIds.begin(), m_impl->m_visibleEntityIds.end(), m_impl->m_visibleEntityDatas.begin(), + m_impl->m_visibleEntityDatas.end(), std::back_inserter(added), EntityDataComparer()); // find entities that are not visible this frame but were last frame AZStd::vector removed; std::set_difference( - m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), - m_impl->m_visibleEntityIds.begin(), m_impl->m_visibleEntityIds.end(), - std::back_inserter(removed), EntityDataComparer()); + m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), m_impl->m_visibleEntityIds.begin(), + m_impl->m_visibleEntityIds.end(), std::back_inserter(removed), EntityDataComparer()); // search for entityData in removed list, return true if it is found const auto removePredicate = [&removed](const EntityData& entityData) { - const auto removeIt = std::equal_range( - removed.begin(), removed.end(), entityData); + const auto removeIt = std::equal_range(removed.begin(), removed.end(), entityData); return removeIt.first != removeIt.second; }; // erase-remove idiom - bubble entities to be removed to the end, then erase them in one go m_impl->m_visibleEntityDatas.erase( - AZStd::remove_if( - m_impl->m_visibleEntityDatas.begin(), - m_impl->m_visibleEntityDatas.end(), removePredicate), + AZStd::remove_if(m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), removePredicate), m_impl->m_visibleEntityDatas.end()); // for newly added entities, request their initial state when first cached @@ -240,8 +237,7 @@ namespace AzToolsFramework return m_impl->m_visibleEntityDatas[index].m_entityId; } - EditorVisibleEntityDataCache::ComponentEntityAccentType EditorVisibleEntityDataCache::GetVisibleEntityAccent( - const size_t index) const + EditorVisibleEntityDataCache::ComponentEntityAccentType EditorVisibleEntityDataCache::GetVisibleEntityAccent(const size_t index) const { return m_impl->m_visibleEntityDatas[index].m_accent; } @@ -273,8 +269,8 @@ namespace AzToolsFramework AZStd::optional EditorVisibleEntityDataCache::GetVisibleEntityIndexFromId(const AZ::EntityId entityId) const { - const auto entityIdIt = std::equal_range( - m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), entityId, EntityDataComparer()); + const auto entityIdIt = + std::equal_range(m_impl->m_visibleEntityDatas.begin(), m_impl->m_visibleEntityDatas.end(), entityId, EntityDataComparer()); if (entityIdIt.first != entityIdIt.second) { @@ -318,8 +314,7 @@ namespace AzToolsFramework } } - void EditorVisibleEntityDataCache::OnTransformChanged( - const AZ::Transform& /*local*/, const AZ::Transform& world) + void EditorVisibleEntityDataCache::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -367,8 +362,7 @@ namespace AzToolsFramework } } - void EditorVisibleEntityDataCache::OnEntityIconChanged( - const AZ::Data::AssetId& /*entityIconAssetId*/) + void EditorVisibleEntityDataCache::OnEntityIconChanged(const AZ::Data::AssetId& /*entityIconAssetId*/) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h index 72c1595e7b..0d74825bf8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h @@ -1,14 +1,14 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once @@ -22,8 +22,8 @@ namespace AzToolsFramework { - /// A cache of packed EntityData that can be iterated over efficiently without - /// the need to make individual EBus calls + //! A cache of packed EntityData that can be iterated over efficiently without + //! the need to make individual EBus calls class EditorVisibleEntityDataCache : private EditorEntityVisibilityNotificationBus::Router , private EditorEntityLockComponentNotificationBus::Router @@ -45,7 +45,7 @@ namespace AzToolsFramework void CalculateVisibleEntityDatas(const AzFramework::ViewportInfo& viewportInfo); - /// EditorVisibleEntityDataCache interface + //! EditorVisibleEntityDataCache interface size_t VisibleEntityDataCount() const; AZ::Vector3 GetVisibleEntityPosition(size_t index) const; const AZ::Transform& GetVisibleEntityTransform(size_t index) const; @@ -72,8 +72,7 @@ namespace AzToolsFramework void OnEntityLockChanged(bool locked) override; // TransformNotificationBus - void OnTransformChanged( - const AZ::Transform& local, const AZ::Transform& world) override; + void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; // EditorComponentSelectionNotificationsBus void OnAccentTypeChanged(EntityAccentType accent) override; @@ -86,6 +85,6 @@ namespace AzToolsFramework void OnEntityIconChanged(const AZ::Data::AssetId& entityIconAssetId) override; class EditorVisibleEntityDataCacheImpl; - AZStd::unique_ptr m_impl; ///< Internal representation of entity data cache. + AZStd::unique_ptr m_impl; //!< Internal representation of entity data cache. }; } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/Tests/ComponentModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/ComponentModeTests.cpp index a4ee80fa5f..45699ddb78 100644 --- a/Code/Framework/AzToolsFramework/Tests/ComponentModeTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ComponentModeTests.cpp @@ -1,30 +1,31 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #include "ComponentModeTestDoubles.h" #include "ComponentModeTestFixture.h" #include +#include #include #include #include -#include #include +#include #include #include #include #include -#include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include namespace UnitTest @@ -47,19 +47,16 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Given QWidget rootWidget; - ActionOverrideRequestBus::Event( - GetEntityContextId(), &ActionOverrideRequests::SetupActionOverrideHandler, &rootWidget); + ActionOverrideRequestBus::Event(GetEntityContextId(), &ActionOverrideRequests::SetupActionOverrideHandler, &rootWidget); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::BeginComponentMode, - AZStd::vector{}); + &ComponentModeSystemRequests::BeginComponentMode, AZStd::vector{}); bool inComponentMode = false; - ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &ComponentModeSystemRequests::InComponentMode); + ComponentModeSystemRequestBus::BroadcastResult(inComponentMode, &ComponentModeSystemRequests::InComponentMode); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -69,11 +66,9 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When - ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::EndComponentMode); + ComponentModeSystemRequestBus::Broadcast(&ComponentModeSystemRequests::EndComponentMode); - ComponentModeSystemRequestBus::BroadcastResult( - inComponentMode, &ComponentModeSystemRequests::InComponentMode); + ComponentModeSystemRequestBus::BroadcastResult(inComponentMode, &ComponentModeSystemRequests::InComponentMode); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -81,8 +76,7 @@ namespace UnitTest EXPECT_FALSE(inComponentMode); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ActionOverrideRequestBus::Event( - GetEntityContextId(), &ActionOverrideRequests::TeardownActionOverrideHandler); + ActionOverrideRequestBus::Event(GetEntityContextId(), &ActionOverrideRequests::TeardownActionOverrideHandler); } TEST_F(ComponentModeTestFixture, TwoComponentsOnSingleEntityWithSameComponentModeBothBegin) @@ -104,8 +98,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -113,8 +106,7 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -152,8 +144,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -161,8 +152,7 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -202,8 +192,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -211,16 +200,13 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); bool nextModeCycled = true; - ComponentModeSystemRequestBus::BroadcastResult( - nextModeCycled, &ComponentModeSystemRequests::SelectNextActiveComponentMode); + ComponentModeSystemRequestBus::BroadcastResult(nextModeCycled, &ComponentModeSystemRequests::SelectNextActiveComponentMode); bool previousModeCycled = true; - ComponentModeSystemRequestBus::BroadcastResult( - previousModeCycled, &ComponentModeSystemRequests::SelectPreviousActiveComponentMode); + ComponentModeSystemRequestBus::BroadcastResult(previousModeCycled, &ComponentModeSystemRequests::SelectPreviousActiveComponentMode); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -250,8 +236,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -259,15 +244,13 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then bool multipleComponentModeTypes = true; - ComponentModeSystemRequestBus::BroadcastResult( - multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); + ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); EXPECT_FALSE(multipleComponentModeTypes); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -294,8 +277,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -303,15 +285,13 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then bool multipleComponentModeTypes = true; - ComponentModeSystemRequestBus::BroadcastResult( - multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); + ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); EXPECT_FALSE(multipleComponentModeTypes); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -341,8 +321,7 @@ namespace UnitTest // mimic selecting the entity in the viewport (after selection the ComponentModeDelegate // connects to the ComponentModeDelegateRequestBus on the entity/component pair address) const AzToolsFramework::EntityIdList entityIds = { entityId }; - ToolsApplicationRequestBus::Broadcast( - &ToolsApplicationRequests::SetSelectedEntities, entityIds); + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, entityIds); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -350,15 +329,13 @@ namespace UnitTest // move all selected components into ComponentMode // (mimic pressing the 'Edit' button to begin Component Mode) ComponentModeSystemRequestBus::Broadcast( - &ComponentModeSystemRequests::AddSelectedComponentModesOfType, - AZ::AzTypeInfo::Uuid()); + &ComponentModeSystemRequests::AddSelectedComponentModesOfType, AZ::AzTypeInfo::Uuid()); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then bool multipleComponentModeTypes = false; - ComponentModeSystemRequestBus::BroadcastResult( - multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); + ComponentModeSystemRequestBus::BroadcastResult(multipleComponentModeTypes, &ComponentModeSystemRequests::HasMultipleComponentTypes); bool secondComponentModeInstantiated = false; ComponentModeSystemRequestBus::BroadcastResult( @@ -366,8 +343,7 @@ namespace UnitTest AZ::EntityComponentIdPair(entityId, placeholder2->GetId())); AZ::Uuid activeComponentType = AZ::Uuid::CreateNull(); - ComponentModeSystemRequestBus::BroadcastResult( - activeComponentType, &ComponentModeSystemRequests::ActiveComponentMode); + ComponentModeSystemRequestBus::BroadcastResult(activeComponentType, &ComponentModeSystemRequests::ActiveComponentMode); EXPECT_TRUE(multipleComponentModeTypes); EXPECT_TRUE(secondComponentModeInstantiated); @@ -412,13 +388,11 @@ namespace UnitTest // Component Mode is will sent the notification to the correct address. ComponentModeActionSignalRequestBus::Event( AZ::EntityComponentIdPair(entityId, placeholder1->GetId()), - &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, - checkerBusId); + &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, checkerBusId); ComponentModeActionSignalRequestBus::Event( AZ::EntityComponentIdPair(entityId, placeholder2->GetId()), - &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, - checkerBusId); + &ComponentModeActionSignalRequests::SetComponentModeActionNotificationBusToNotify, checkerBusId); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -470,8 +444,7 @@ namespace UnitTest using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult; MouseInteractionResult handled = MouseInteractionResult::None; EditorInteractionSystemViewportSelectionRequestBus::BroadcastResult( - handled, &EditorInteractionSystemViewportSelectionRequestBus::Events::InternalHandleAllMouseInteractions, - interactionEvent); + handled, &EditorInteractionSystemViewportSelectionRequestBus::Events::InternalHandleAllMouseInteractions, interactionEvent); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -482,8 +455,7 @@ namespace UnitTest } // Test version of EntityPropertyEditor to detect/ensure certain functions were called - class TestEntityPropertyEditor - : public AzToolsFramework::EntityPropertyEditor + class TestEntityPropertyEditor : public AzToolsFramework::EntityPropertyEditor { public: void InvalidatePropertyDisplay(PropertyModificationRefreshLevel level) override; @@ -496,8 +468,7 @@ namespace UnitTest } // Simple fixture to encapsulate a TestEntityPropertyEditor - class ComponentModePinnedSelectionFixture - : public ToolsApplicationFixture + class ComponentModePinnedSelectionFixture : public ToolsApplicationFixture { public: void SetUpEditorFixtureImpl() override @@ -533,7 +504,7 @@ namespace UnitTest /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When // select entity - const auto selectedEntities = AzToolsFramework::EntityIdList { entityId }; + const auto selectedEntities = AzToolsFramework::EntityIdList{ entityId }; SelectEntities(selectedEntities); // pin entity @@ -549,8 +520,7 @@ namespace UnitTest EXPECT_TRUE(m_testEntityPropertyEditor->IsLockedToSpecificEntities()); EXPECT_TRUE(m_testEntityPropertyEditor->m_invalidatePropertyDisplayCalled); - bool couldBeginComponentMode = - AzToolsFramework::ComponentModeFramework::CouldBeginComponentModeWithEntity(entityId); + bool couldBeginComponentMode = AzToolsFramework::ComponentModeFramework::CouldBeginComponentModeWithEntity(entityId); EXPECT_FALSE(couldBeginComponentMode); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -566,29 +536,26 @@ namespace UnitTest entity->Deactivate(); AzToolsFramework::EntityCompositionRequestBus::Broadcast( - &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, - AzToolsFramework::EntityIdList{entityId}, + &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId }, AZ::ComponentTypeList{ AZ::AzTypeInfo::Uuid() }); AzToolsFramework::EntityCompositionRequestBus::Broadcast( - &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, - AzToolsFramework::EntityIdList{entityId}, - AZ::ComponentTypeList{AZ::AzTypeInfo::Uuid()}); + &AzToolsFramework::EntityCompositionRequestBus::Events::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId }, + AZ::ComponentTypeList{ AZ::AzTypeInfo::Uuid() }); entity->Activate(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // When - SelectEntities(AzToolsFramework::EntityIdList{entityId}); + SelectEntities(AzToolsFramework::EntityIdList{ entityId }); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Then AZ::Entity::ComponentArrayType pendingComponents; AzToolsFramework::EditorPendingCompositionRequestBus::Event( - entityId, &AzToolsFramework::EditorPendingCompositionRequestBus::Events::GetPendingComponents, - pendingComponents); + entityId, &AzToolsFramework::EditorPendingCompositionRequestBus::Events::GetPendingComponents, pendingComponents); // ensure we do have pending components EXPECT_EQ(pendingComponents.size(), 1); From 1a6b6d5bc0e90ac9c2691124f2240e8cfef3123a Mon Sep 17 00:00:00 2001 From: jackalbe <23512001+jackalbe@users.noreply.github.com> Date: Mon, 7 Jun 2021 09:04:37 -0500 Subject: [PATCH 139/153] {LYN-4230} Fixed loading *.pak files in Release builds (#1127) * {LYN-4230} Fixed loading *.pak files in Release builds * Helios - Release mode should load all *.pak files * Tests: made a separate installation folder with a reduced "engine.pak" and a full "game.pak" which loads in release * added unit test to regress the bug fix --- .../AzFramework/Archive/Archive.cpp | 12 +++---- Code/Framework/Tests/ArchiveTests.cpp | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index 4a80db2b24..04573eb2e5 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1681,13 +1681,11 @@ namespace AZ::IO AZStd::vector files; do { - if (AZStd::wildcard_match(pWildcardIn, fileIterator.m_filename)) - { - AZStd::string foundFilename{ fileIterator.m_filename }; - AZStd::to_lower(foundFilename.begin(), foundFilename.end()); - files.emplace_back(AZStd::move(foundFilename)); - } - } while (fileIterator = FindNext(fileIterator)); + AZStd::string foundFilename{ fileIterator.m_filename }; + AZStd::to_lower(foundFilename.begin(), foundFilename.end()); + files.emplace_back(AZStd::move(foundFilename)); + } + while (fileIterator = FindNext(fileIterator)); // Open files in alphabet order. AZStd::sort(files.begin(), files.end()); diff --git a/Code/Framework/Tests/ArchiveTests.cpp b/Code/Framework/Tests/ArchiveTests.cpp index 6dc081ee72..ddc7060083 100644 --- a/Code/Framework/Tests/ArchiveTests.cpp +++ b/Code/Framework/Tests/ArchiveTests.cpp @@ -281,6 +281,39 @@ namespace UnitTest TestFGetCachedFileData(fileInArchiveFile, dataString.size(), dataString.data()); } + TEST_F(ArchiveTestFixture, TestArchiveOpenPacks_FindsMultiplePaks_Works) + { + AZ::IO::IArchive* archive = AZ::Interface::Get(); + ASSERT_NE(nullptr, archive); + + AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance(); + ASSERT_NE(nullptr, fileIo); + + auto resetArchiveFile = [archive, fileIo](const AZStd::string& filePath) + { + archive->ClosePack(filePath.c_str()); + fileIo->Remove(filePath.c_str()); + + auto pArchive = archive->OpenArchive(filePath.c_str(), nullptr, AZ::IO::INestedArchive::FLAGS_CREATE_NEW); + EXPECT_NE(nullptr, pArchive); + pArchive.reset(); + archive->ClosePack(filePath.c_str()); + }; + + AZStd::string testArchivePath_pakOne = "@usercache@/one.pak"; + AZStd::string testArchivePath_pakTwo = "@usercache@/two.pak"; + + // reset test files in case they already exist + resetArchiveFile(testArchivePath_pakOne); + resetArchiveFile(testArchivePath_pakTwo); + + // open and fetch the opened pak file using a *.pak + AZStd::vector fullPaths; + archive->OpenPacks("@usercache@/*.pak", AZ::IO::IArchive::EPathResolutionRules::FLAGS_PATH_REAL, &fullPaths); + EXPECT_TRUE(AZStd::any_of(fullPaths.cbegin(), fullPaths.cend(), [](auto& path) { return path.ends_with("one.pak"); })); + EXPECT_TRUE(AZStd::any_of(fullPaths.cbegin(), fullPaths.cend(), [](auto& path) { return path.ends_with("two.pak"); })); + } + TEST_F(ArchiveTestFixture, TestArchiveFGetCachedFileData_LooseFile) { // ------setup loose file FGetCachedFileData tests ------------------------- From 9e3d4727003eff4e008d635512506214016a8bb3 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Mon, 7 Jun 2021 09:21:10 -0700 Subject: [PATCH 140/153] Switch EditorContextMenu back to using popup instead of exec (#1158) Switch EditorContextMenu back to using popup instead of exec The switch to exec was a deliberate change, but upon further testing with the latest version of our camera input controllers (both the Legacy and Modern variants) it is no longer necessary to call exec, and doing so can cause a bug in which the cursor is still hidden when the context menu appears. --- .../AzToolsFramework/Viewport/EditorContextMenu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp index 8ed488b010..308f0f074f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/EditorContextMenu.cpp @@ -62,7 +62,8 @@ namespace AzToolsFramework if (!contextMenu.m_menu->isEmpty()) { - contextMenu.m_menu->exec(QCursor::pos()); + // Use popup instead of exec; this avoids blocking input event processing while the menu dialog is active + contextMenu.m_menu->popup(QCursor::pos()); } } } From 6d6f8413c8fa260ff2dec8dc1aaa674125a915ad Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 7 Jun 2021 14:14:32 -0400 Subject: [PATCH 141/153] Incorporating review comments. Some parameter modifications. Some cli edge case handling. Remove remove_tag member from project info --- .../ProjectManager/Source/ProjectInfo.cpp | 2 - .../Tools/ProjectManager/Source/ProjectInfo.h | 14 ++++--- .../ProjectManager/Source/PythonBindings.cpp | 20 +++++----- scripts/o3de/o3de/project_properties.py | 39 +++++++++++-------- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index 85716fccfa..99649cbfdf 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -26,8 +26,6 @@ namespace O3DE::ProjectManager , m_backgroundImagePath(backgroundImagePath) , m_needsBuild(needsBuild) { - m_userTags = QStringList(); - m_userTagsForRemoval = QStringList(); } bool ProjectInfo::operator==(const ProjectInfo& rhs) diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index 47a10dbc14..184916a514 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -25,8 +25,15 @@ namespace O3DE::ProjectManager public: ProjectInfo() = default; - ProjectInfo(const QString& path, const QString& projectName, const QString& displayName, const QString& origin, - const QString& summary, const QString& imagePath, const QString& backgroundImagePath, bool needsBuild + ProjectInfo( + const QString& path, + const QString& projectName, + const QString& displayName, + const QString& origin, + const QString& summary, + const QString& imagePath, + const QString& backgroundImagePath, + bool needsBuild); bool operator==(const ProjectInfo& rhs); bool operator!=(const ProjectInfo& rhs); @@ -49,9 +56,6 @@ namespace O3DE::ProjectManager // Used in project creation - // Used to flag tags for removal - QStringList m_userTagsForRemoval; - bool m_needsBuild = false; //! Does this project need to be built }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 9fa10ce3d8..fe01209172 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,6 +53,7 @@ namespace Platform #define Py_To_String(obj) obj.cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string +#define Py_To_List(obj) obj.cast> namespace RedirectOutput { @@ -678,6 +679,12 @@ namespace O3DE::ProjectManager { projectInfo.m_projectName = Py_To_String(projectData["project_name"]); projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); + projectInfo.m_origin = Py_To_String_Optional(projectData, "origin", projectInfo.m_origin); + projectInfo.m_summary = Py_To_String_Optional(projectData, "summary", projectInfo.m_summary); + for (const auto& tag : projectData["user_tags"]) + { + projectInfo.m_userTags.append(Py_To_String(tag)); + } } catch ([[maybe_unused]] const std::exception& e) { @@ -753,17 +760,11 @@ namespace O3DE::ProjectManager return ExecuteWithLockErrorHandling([&] { std::list newTags; - for (auto& i : projectInfo.m_userTags) + for (const auto& i : projectInfo.m_userTags) { newTags.push_back(i.toStdString()); } - std::list removedTags; - for (auto& i : projectInfo.m_userTagsForRemoval) - { - removedTags.push_back(i.toStdString()); - } - m_editProjectProperties.attr("edit_project_props")( pybind11::str(projectInfo.m_path.toStdString()), // proj_path pybind11::none(), // proj_name not used @@ -771,8 +772,9 @@ namespace O3DE::ProjectManager pybind11::str(projectInfo.m_displayName.toStdString()), // new_display pybind11::str(projectInfo.m_summary.toStdString()), // new_summary pybind11::str(projectInfo.m_imagePath.toStdString()), // new_icon - pybind11::list(pybind11::cast(newTags)), // new_tag - pybind11::list(pybind11::cast(removedTags))); // remove_tag + pybind11::none(), // add_tags not used + pybind11::none(), // remove_tags not used + pybind11::list(pybind11::cast(newTags))); // replace_tags }); } diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index 83e76fc18f..b2268131c0 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -30,7 +30,7 @@ def get_project_props(name: str = None, path: pathlib.Path = None) -> dict: return proj_json def edit_project_props(proj_path, proj_name, new_origin, new_display, - new_summary, new_icon, new_tag, remove_tag) -> int: + new_summary, new_icon, new_tags, delete_tags, replace_tags) -> int: proj_json = get_project_props(proj_name, proj_path) if not proj_json: @@ -44,18 +44,22 @@ def edit_project_props(proj_path, proj_name, new_origin, new_display, proj_json['summary'] = new_summary if new_icon: proj_json['icon_path'] = new_icon - if new_tag: - for tag in new_tag: - proj_json.setdefault('user_tags', []).append(tag) - if remove_tag: + if new_tags: + tag_list = [new_tags] if isinstance(new_tags, str) else new_tags + proj_json.setdefault('user_tags', []).extend(tag_list) + if delete_tags: + removal_list = [delete_tags] if isinstance(delete_tags, str) else delete_tags if 'user_tags' in proj_json: - for del_tag in remove_tag: - if del_tag in proj_json['user_tags']: - proj_json['user_tags'].remove(del_tag) + for tag in removal_list: + if tag in proj_json['user_tags']: + proj_json['user_tags'].remove(tag) else: - logger.warn(f'{del_tag} not found in user_tags for removal.') + logger.warn(f'{tag} not found in user_tags for removal.') else: - logger.warn(f'user_tags property not found for removal of {remove_tag}.') + logger.warn(f'user_tags property not found for removal of {remove_tags}.') + if replace_tags: + tag_list = [replace_tags] if isinstance(replace_tags, str) else replace_tags + proj_json['user_tags'] = tag_list manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json') return 0 @@ -67,8 +71,9 @@ def _edit_project_props(args: argparse) -> int: args.project_display, args.project_summary, args.project_icon, - args.project_tag, - args.remove_tag) + args.add_tags, + args.delete_tags, + args.replace_tags) def add_parser_args(parser): group = parser.add_mutually_exclusive_group(required=True) @@ -85,10 +90,12 @@ def add_parser_args(parser): help='Sets the summary description of the project.') group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') - group.add_argument('-pt', '--project-tag', type=default, required=False, - help='Adds tag(s) to user_tags property. These tags are intended for documentation and filtering.') - group.add_argument('-rt', '--remove-tag', type=default, required=False, - help='Removes tag(s) from the user_tags property.') + group.add_argument('-at', '--add-tags', type=str, nargs='*', required=False, + help='Adds tag(s) to user_tags property. Space delimited list (ex. -at A B C)') + group.add_argument('-dt', '--delete-tags', type=str, nargs ='*', required=False, + help='Removes tag(s) from the user_tags property. Space delimited list (ex. -dt A B C') + group.add_argument('-rt', '--replace-tags', type=str, nargs ='*', required=False, + help='Replace entirety of user_tags proeprty with space delimited list of values') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: From 01b200ad42ddf57386cea3ad44c9121e286e2477 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 7 Jun 2021 14:19:48 -0400 Subject: [PATCH 142/153] removing unused define --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index fe01209172..1db8c92d3f 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,7 +53,6 @@ namespace Platform #define Py_To_String(obj) obj.cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string -#define Py_To_List(obj) obj.cast> namespace RedirectOutput { From b0826c5f9cdeb3d2d51d23fec5aaea5c6eaa0302 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 7 Jun 2021 15:08:18 -0400 Subject: [PATCH 143/153] added tag managerment arguments for CLI to mutually exclusive group --- scripts/o3de/o3de/project_properties.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/project_properties.py b/scripts/o3de/o3de/project_properties.py index b2268131c0..52f1346b51 100644 --- a/scripts/o3de/o3de/project_properties.py +++ b/scripts/o3de/o3de/project_properties.py @@ -90,12 +90,13 @@ def add_parser_args(parser): help='Sets the summary description of the project.') group.add_argument('-pi', '--project-icon', type=str, required=False, help='Sets the path to the projects icon resource.') + group = parser.add_mutually_exclusive_group(required=False) group.add_argument('-at', '--add-tags', type=str, nargs='*', required=False, help='Adds tag(s) to user_tags property. Space delimited list (ex. -at A B C)') group.add_argument('-dt', '--delete-tags', type=str, nargs ='*', required=False, help='Removes tag(s) from the user_tags property. Space delimited list (ex. -dt A B C') group.add_argument('-rt', '--replace-tags', type=str, nargs ='*', required=False, - help='Replace entirety of user_tags proeprty with space delimited list of values') + help='Replace entirety of user_tags property with space delimited list of values') parser.set_defaults(func=_edit_project_props) def add_args(subparsers) -> None: From 1900a422035dcb16fa82144d6a59f630ab9fe952 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 7 Jun 2021 15:43:47 -0400 Subject: [PATCH 144/153] remove const ref from iterator for python object conversion since pybind only returns copies and produces a clang error --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 1db8c92d3f..5d1463598a 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -680,7 +680,7 @@ namespace O3DE::ProjectManager projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); projectInfo.m_origin = Py_To_String_Optional(projectData, "origin", projectInfo.m_origin); projectInfo.m_summary = Py_To_String_Optional(projectData, "summary", projectInfo.m_summary); - for (const auto& tag : projectData["user_tags"]) + for (auto tag : projectData["user_tags"]) { projectInfo.m_userTags.append(Py_To_String(tag)); } From 36cb0f6d40d4ae756dbf878dd5b99b2611038ef0 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 7 Jun 2021 15:59:58 -0700 Subject: [PATCH 145/153] SPEC-7178 Removal of precompiled cpp files (#1171) * SPEC-7178 Removal of precompiled cpp files * Missing files... --- .../CrySystem/CrySystem_precompiled.cpp | 14 -------------- Code/CryEngine/CrySystem/crysystem_files.cmake | 1 - .../AzToolsFramework_precompiled.cpp | 13 ------------- .../aztoolsframework_files.cmake | 1 - .../ComponentEntityEditorPlugin_precompiled.cpp | 12 ------------ .../componententityeditorplugin_files.cmake | 1 - .../EditorAssetImporter_precompiled.cpp | 15 --------------- .../editorassetimporter_files.cmake | 1 - .../FFMPEGPlugin/FFMPEGPlugin_precompiled.cpp | 13 ------------- .../FFMPEGPlugin/ffmpegplugin_files.cmake | 1 - .../PerforcePlugin_precompiled.cpp | 15 --------------- .../PerforcePlugin/perforceplugin_files.cmake | 1 - .../ProjectSettingsTool_precompiled.cpp | 12 ------------ .../projectsettingstool_files.cmake | 1 - .../Standalone/StandaloneTools_precompiled.cpp | 14 -------------- .../Standalone/standalone_tools_files.cmake | 1 - .../Source/AssetMemoryAnalyzer_precompiled.cpp | 12 ------------ .../Code/assetmemoryanalyzer_files.cmake | 1 - .../Code/Source/ImageProcessing_precompiled.cpp | 13 ------------- .../Code/imageprocessing_files.cmake | 1 - .../Source/RHI/Atom_RHI_DX12_precompiled.cpp | 12 ------------ .../atom_rhi_dx12_private_common_files.cmake | 1 - .../Code/Source/Atom_RHI_Metal_precompiled.cpp | 12 ------------ .../Code/atom_rhi_metal_common_files.cmake | 1 - .../Code/Source/Atom_RHI_Null_precompiled.cpp | 12 ------------ .../Null/Code/atom_rhi_null_common_files.cmake | 1 - .../Code/Source/Atom_RHI_Vulkan_precompiled.cpp | 12 ------------ .../Code/atom_rhi_vulkan_common_files.cmake | 1 - .../Code/Source/AtomFont_precompiled.cpp | 14 -------------- .../AtomFont/Code/atomfont_files.cmake | 1 - Gems/Camera/Code/Source/Camera_precompiled.cpp | 12 ------------ Gems/Camera/Code/camera_files.cmake | 1 - .../Code/Source/CameraFramework_precompiled.cpp | 12 ------------ .../Code/cameraframework_files.cmake | 1 - .../Code/Source/DebugDraw_precompiled.cpp | 13 ------------- .../DebugDraw/Code/debugdraw_editor_files.cmake | 1 - Gems/DebugDraw/Code/debugdraw_files.cmake | 1 - .../Rendering/OpenGL2/Source/GLExtensions.h | 1 + .../Code/Source/EMotionFX_precompiled.cpp | 14 -------------- .../EMotionFX/Code/emotionfx_editor_files.cmake | 1 - Gems/EMotionFX/Code/emotionfx_files.cmake | 1 - .../Code/Source/FastNoise_precompiled.cpp | 12 ------------ Gems/FastNoise/Code/fastnoise_files.cmake | 1 - .../Code/Source/Gestures_precompiled.cpp | 12 ------------ Gems/Gestures/Code/gestures_files.cmake | 1 - .../Code/Source/GradientSignal_precompiled.cpp | 12 ------------ .../Code/gradientsignal_files.cmake | 1 - Gems/GraphCanvas/Code/graphcanvas_files.cmake | 1 - Gems/GraphCanvas/Code/precompiled.cpp | 14 -------------- .../Code/Source/HttpRequestor_precompiled.cpp | 13 ------------- .../Code/httprequestor_files.cmake | 1 - .../Code/lmbraws_unsupported_files.cmake | 1 - Gems/ImGui/Code/Source/ImGui_precompiled.cpp | 12 ------------ Gems/ImGui/Code/imgui_common_files.cmake | 1 - .../ImGui/Code/imgui_lyutils_static_files.cmake | 1 - .../Code/Source/InAppPurchases_precompiled.cpp | 13 ------------- .../Code/inapppurchases_files.cmake | 1 - .../Code/Source/LmbrCentral_precompiled.cpp | 13 ------------- Gems/LmbrCentral/Code/lmbrcentral_files.cmake | 1 - .../Code/Editor/UiCanvasEditor_precompiled.cpp | 12 ------------ .../Source/Animation/LyShine_precompiled.cpp | 13 ------------- .../LyShine/Code/Source/LyShine_precompiled.cpp | 13 ------------- Gems/LyShine/Code/lyshine_static_files.cmake | 1 - .../Code/lyshine_uicanvaseditor_files.cmake | 1 - .../Code/Source/LyShineExamples_precompiled.cpp | 13 ------------- .../Code/lyshineexamples_files.cmake | 1 - .../Source/Cinematics/Maestro_precompiled.cpp | 14 -------------- .../Maestro/Code/Source/Maestro_precompiled.cpp | 12 ------------ Gems/Maestro/Code/maestro_static_files.cmake | 1 - .../Code/Source/MessagePopup_precompiled.cpp | 12 ------------ Gems/MessagePopup/Code/messagepopup_files.cmake | 1 - .../Code/Source/Metastream_precompiled.cpp | 12 ------------ Gems/Metastream/Code/metastream_files.cmake | 1 - .../Code/Source/Microphone_precompiled.cpp | 13 ------------- Gems/Microphone/Code/microphone_files.cmake | 1 - .../Code/Source/Multiplayer_precompiled.cpp | 13 ------------- .../Code/multiplayer_debug_files.cmake | 1 - Gems/Multiplayer/Code/multiplayer_files.cmake | 1 - .../Code/multiplayer_tools_files.cmake | 1 - .../Source/NumericalMethods_precompiled.cpp | 13 ------------- .../numericalmethods_files.cmake | 1 - .../Source/PhysXUnsupported_precompiled.cpp | 13 ------------- Gems/PhysX/Code/Source/PhysX_precompiled.cpp | 13 ------------- Gems/PhysX/Code/physx_files.cmake | 1 - .../PhysXDebugUnsupported_precompiled.cpp | 13 ------------- .../Code/Source/PhysXDebug_precompiled.cpp | 12 ------------ .../Code/physxdebug_editor_files.cmake | 1 - Gems/PhysXDebug/Code/physxdebug_files.cmake | 1 - .../Code/physxdebug_unsupported_files.cmake | 1 - Gems/ScriptCanvas/Code/Editor/precompiled.cpp | 13 ------------- Gems/ScriptCanvas/Code/Source/precompiled.cpp | 13 ------------- .../Code/scriptcanvasgem_editor_files.cmake | 1 - .../scriptcanvasgem_editor_shared_files.cmake | 1 - .../Code/scriptcanvasgem_game_files.cmake | 1 - .../Code/scriptcanvasgem_tests_files.cmake | 1 - .../Code/Source/precompiled.cpp | 13 ------------- ...scriptcanvasdeveloper_gem_common_files.cmake | 1 - .../Source/ScriptCanvasPhysics_precompiled.cpp | 13 ------------- .../Code/scriptcanvas_physics_files.cmake | 1 - .../scriptcanvas_physics_shared_files.cmake | 1 - Gems/ScriptEvents/Code/Source/precompiled.cpp | 13 ------------- .../Code/scriptevents_editor_files.cmake | 1 - Gems/ScriptEvents/Code/scriptevents_files.cmake | 1 - .../ScriptedEntityTweener_precompiled.cpp | 13 ------------- .../Code/scriptedentitytweener_files.cmake | 1 - .../Code/Source/SliceFavorites_precompiled.cpp | 13 ------------- .../Code/slicefavorites_files.cmake | 1 - .../Source/StartingPointCamera_precompiled.cpp | 12 ------------ .../Code/startingpointcamera_files.cmake | 1 - .../Source/StartingPointInput_precompiled.cpp | 12 ------------ .../Code/startingpointinput_editor_files.cmake | 2 -- .../Code/startingpointinput_files.cmake | 1 - Gems/StartingPointMovement/Code/CMakeLists.txt | 16 ---------------- .../StartingPointMovement_precompiled.cpp | 12 ------------ .../Code/startingpointmovement_files.cmake | 17 ----------------- .../startingpointmovement_shared_files.cmake | 3 +++ .../Code/Source/SurfaceData_precompiled.cpp | 12 ------------ Gems/SurfaceData/Code/surfacedata_files.cmake | 1 - .../Code/Source/TextureAtlas_precompiled.cpp | 13 ------------- Gems/TextureAtlas/Code/textureatlas_files.cmake | 1 - .../Source/TickBusOrderViewer_precompiled.cpp | 12 ------------ .../Code/tickbusorderviewer_files.cmake | 1 - Gems/Twitch/Code/Source/Twitch_precompiled.cpp | 13 ------------- .../Twitch/Code/lmbraws_unsupported_files.cmake | 1 - Gems/Twitch/Code/twitch_files.cmake | 1 - .../Code/Source/Vegetation_precompiled.cpp | 12 ------------ Gems/Vegetation/Code/vegetation_files.cmake | 1 - .../Code/Source/VirtualGamepad_precompiled.cpp | 13 ------------- .../Code/virtualgamepad_files.cmake | 1 - .../Source/WhiteBoxUnsupported_precompiled.cpp | 13 ------------- .../Code/Source/WhiteBox_precompiled.cpp | 13 ------------- .../Code/whitebox_supported_files.cmake | 1 - .../Code/whitebox_unsupported_files.cmake | 1 - 133 files changed, 4 insertions(+), 869 deletions(-) delete mode 100644 Code/CryEngine/CrySystem/CrySystem_precompiled.cpp delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.cpp delete mode 100644 Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.cpp delete mode 100644 Code/Sandbox/Plugins/EditorAssetImporter/EditorAssetImporter_precompiled.cpp delete mode 100644 Code/Sandbox/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.cpp delete mode 100644 Code/Sandbox/Plugins/PerforcePlugin/PerforcePlugin_precompiled.cpp delete mode 100644 Code/Sandbox/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.cpp delete mode 100644 Code/Tools/Standalone/StandaloneTools_precompiled.cpp delete mode 100644 Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.cpp delete mode 100644 Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.cpp delete mode 100644 Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.cpp delete mode 100644 Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.cpp delete mode 100644 Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.cpp delete mode 100644 Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.cpp delete mode 100644 Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont_precompiled.cpp delete mode 100644 Gems/Camera/Code/Source/Camera_precompiled.cpp delete mode 100644 Gems/CameraFramework/Code/Source/CameraFramework_precompiled.cpp delete mode 100644 Gems/DebugDraw/Code/Source/DebugDraw_precompiled.cpp delete mode 100644 Gems/EMotionFX/Code/Source/EMotionFX_precompiled.cpp delete mode 100644 Gems/FastNoise/Code/Source/FastNoise_precompiled.cpp delete mode 100644 Gems/Gestures/Code/Source/Gestures_precompiled.cpp delete mode 100644 Gems/GradientSignal/Code/Source/GradientSignal_precompiled.cpp delete mode 100644 Gems/GraphCanvas/Code/precompiled.cpp delete mode 100644 Gems/HttpRequestor/Code/Source/HttpRequestor_precompiled.cpp delete mode 100644 Gems/ImGui/Code/Source/ImGui_precompiled.cpp delete mode 100644 Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.cpp delete mode 100644 Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.cpp delete mode 100644 Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.cpp delete mode 100644 Gems/LyShine/Code/Source/Animation/LyShine_precompiled.cpp delete mode 100644 Gems/LyShine/Code/Source/LyShine_precompiled.cpp delete mode 100644 Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.cpp delete mode 100644 Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.cpp delete mode 100644 Gems/Maestro/Code/Source/Maestro_precompiled.cpp delete mode 100644 Gems/MessagePopup/Code/Source/MessagePopup_precompiled.cpp delete mode 100644 Gems/Metastream/Code/Source/Metastream_precompiled.cpp delete mode 100644 Gems/Microphone/Code/Source/Microphone_precompiled.cpp delete mode 100644 Gems/Multiplayer/Code/Source/Multiplayer_precompiled.cpp delete mode 100644 Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.cpp delete mode 100644 Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.cpp delete mode 100644 Gems/PhysX/Code/Source/PhysX_precompiled.cpp delete mode 100644 Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.cpp delete mode 100644 Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.cpp delete mode 100644 Gems/ScriptCanvas/Code/Editor/precompiled.cpp delete mode 100644 Gems/ScriptCanvas/Code/Source/precompiled.cpp delete mode 100644 Gems/ScriptCanvasDeveloper/Code/Source/precompiled.cpp delete mode 100644 Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.cpp delete mode 100644 Gems/ScriptEvents/Code/Source/precompiled.cpp delete mode 100644 Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.cpp delete mode 100644 Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.cpp delete mode 100644 Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.cpp delete mode 100644 Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.cpp delete mode 100644 Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.cpp delete mode 100644 Gems/StartingPointMovement/Code/startingpointmovement_files.cmake delete mode 100644 Gems/SurfaceData/Code/Source/SurfaceData_precompiled.cpp delete mode 100644 Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.cpp delete mode 100644 Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.cpp delete mode 100644 Gems/Twitch/Code/Source/Twitch_precompiled.cpp delete mode 100644 Gems/Vegetation/Code/Source/Vegetation_precompiled.cpp delete mode 100644 Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.cpp delete mode 100644 Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.cpp delete mode 100644 Gems/WhiteBox/Code/Source/WhiteBox_precompiled.cpp diff --git a/Code/CryEngine/CrySystem/CrySystem_precompiled.cpp b/Code/CryEngine/CrySystem/CrySystem_precompiled.cpp deleted file mode 100644 index eaa80bbdc1..0000000000 --- a/Code/CryEngine/CrySystem/CrySystem_precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -// If you make changes in ICryPak.h, make changes here, to dirty the PCH. -#include "CrySystem_precompiled.h" diff --git a/Code/CryEngine/CrySystem/crysystem_files.cmake b/Code/CryEngine/CrySystem/crysystem_files.cmake index 84250de95b..f0398ffb88 100644 --- a/Code/CryEngine/CrySystem/crysystem_files.cmake +++ b/Code/CryEngine/CrySystem/crysystem_files.cmake @@ -75,6 +75,5 @@ set(FILES ViewSystem/View.h ViewSystem/ViewSystem.cpp ViewSystem/ViewSystem.h - CrySystem_precompiled.cpp WindowsErrorReporting.cpp ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.cpp deleted file mode 100644 index f9de86bce5..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFramework_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "AzToolsFramework_precompiled.h" diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 8d0180f6ce..e5ac1f9693 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -11,7 +11,6 @@ set(FILES AzToolsFramework_precompiled.h - AzToolsFramework_precompiled.cpp AssetEditor/AssetEditorBus.h AssetEditor/AssetEditorToolbar.ui AssetEditor/AssetEditorStatusBar.ui diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.cpp deleted file mode 100644 index ce0194251b..0000000000 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ComponentEntityEditorPlugin_precompiled.h" diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake index 6672bc8b47..2b5877b1e6 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/componententityeditorplugin_files.cmake @@ -15,7 +15,6 @@ set(FILES ComponentEntityEditorPlugin.cpp SandboxIntegration.h SandboxIntegration.cpp - ComponentEntityEditorPlugin_precompiled.cpp ComponentEntityEditorPlugin_precompiled.h UI/ComponentEntityEditorOutlinerWindow.qrc UI/QComponentEntityEditorMainWindow.h diff --git a/Code/Sandbox/Plugins/EditorAssetImporter/EditorAssetImporter_precompiled.cpp b/Code/Sandbox/Plugins/EditorAssetImporter/EditorAssetImporter_precompiled.cpp deleted file mode 100644 index a77146223e..0000000000 --- a/Code/Sandbox/Plugins/EditorAssetImporter/EditorAssetImporter_precompiled.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorAssetImporter_precompiled.h" - diff --git a/Code/Sandbox/Plugins/EditorAssetImporter/editorassetimporter_files.cmake b/Code/Sandbox/Plugins/EditorAssetImporter/editorassetimporter_files.cmake index 68f7a450a1..c017aa6320 100644 --- a/Code/Sandbox/Plugins/EditorAssetImporter/editorassetimporter_files.cmake +++ b/Code/Sandbox/Plugins/EditorAssetImporter/editorassetimporter_files.cmake @@ -23,7 +23,6 @@ set(FILES SceneSerializationHandler.h SceneSerializationHandler.cpp Main.cpp - EditorAssetImporter_precompiled.cpp EditorAssetImporter_precompiled.h AssetImporter.qrc AssetImporterWindow.ui diff --git a/Code/Sandbox/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.cpp b/Code/Sandbox/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.cpp deleted file mode 100644 index b7f4fd23cc..0000000000 --- a/Code/Sandbox/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "FFMPEGPlugin_precompiled.h" - diff --git a/Code/Sandbox/Plugins/FFMPEGPlugin/ffmpegplugin_files.cmake b/Code/Sandbox/Plugins/FFMPEGPlugin/ffmpegplugin_files.cmake index 9ae55cc45a..1c36b4c5bc 100644 --- a/Code/Sandbox/Plugins/FFMPEGPlugin/ffmpegplugin_files.cmake +++ b/Code/Sandbox/Plugins/FFMPEGPlugin/ffmpegplugin_files.cmake @@ -12,7 +12,6 @@ set(FILES FFMPEGPlugin.rc main.cpp - FFMPEGPlugin_precompiled.cpp FFMPEGPlugin_precompiled.h FFMPEGPlugin.cpp FFMPEGPlugin.h diff --git a/Code/Sandbox/Plugins/PerforcePlugin/PerforcePlugin_precompiled.cpp b/Code/Sandbox/Plugins/PerforcePlugin/PerforcePlugin_precompiled.cpp deleted file mode 100644 index cc1ded61a4..0000000000 --- a/Code/Sandbox/Plugins/PerforcePlugin/PerforcePlugin_precompiled.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "PerforcePlugin_precompiled.h" - diff --git a/Code/Sandbox/Plugins/PerforcePlugin/perforceplugin_files.cmake b/Code/Sandbox/Plugins/PerforcePlugin/perforceplugin_files.cmake index 6e3a497aca..11e81d3358 100644 --- a/Code/Sandbox/Plugins/PerforcePlugin/perforceplugin_files.cmake +++ b/Code/Sandbox/Plugins/PerforcePlugin/perforceplugin_files.cmake @@ -20,6 +20,5 @@ set(FILES PerforceSourceControl.cpp PerforceSourceControl.h resource.h - PerforcePlugin_precompiled.cpp PerforcePlugin_precompiled.h ) diff --git a/Code/Sandbox/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.cpp b/Code/Sandbox/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.cpp deleted file mode 100644 index 82549e649a..0000000000 --- a/Code/Sandbox/Plugins/ProjectSettingsTool/ProjectSettingsTool_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ProjectSettingsTool_precompiled.h" diff --git a/Code/Sandbox/Plugins/ProjectSettingsTool/projectsettingstool_files.cmake b/Code/Sandbox/Plugins/ProjectSettingsTool/projectsettingstool_files.cmake index 235109e629..72287be08a 100644 --- a/Code/Sandbox/Plugins/ProjectSettingsTool/projectsettingstool_files.cmake +++ b/Code/Sandbox/Plugins/ProjectSettingsTool/projectsettingstool_files.cmake @@ -11,7 +11,6 @@ set(FILES main.cpp - ProjectSettingsTool_precompiled.cpp ProjectSettingsTool_precompiled.h DefaultImageValidator.cpp DefaultImageValidator.h diff --git a/Code/Tools/Standalone/StandaloneTools_precompiled.cpp b/Code/Tools/Standalone/StandaloneTools_precompiled.cpp deleted file mode 100644 index 073859f9b8..0000000000 --- a/Code/Tools/Standalone/StandaloneTools_precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "StandaloneTools_precompiled.h" - diff --git a/Code/Tools/Standalone/standalone_tools_files.cmake b/Code/Tools/Standalone/standalone_tools_files.cmake index 57e3e45d66..65933bd8c6 100644 --- a/Code/Tools/Standalone/standalone_tools_files.cmake +++ b/Code/Tools/Standalone/standalone_tools_files.cmake @@ -10,7 +10,6 @@ # set(FILES - StandaloneTools_precompiled.cpp StandaloneTools_precompiled.h targetver.h Source/StandaloneToolsApplication.cpp diff --git a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.cpp b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.cpp deleted file mode 100644 index 75643c0cf7..0000000000 --- a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "AssetMemoryAnalyzer_precompiled.h" diff --git a/Gems/AssetMemoryAnalyzer/Code/assetmemoryanalyzer_files.cmake b/Gems/AssetMemoryAnalyzer/Code/assetmemoryanalyzer_files.cmake index 88994a2b47..8119a6e870 100644 --- a/Gems/AssetMemoryAnalyzer/Code/assetmemoryanalyzer_files.cmake +++ b/Gems/AssetMemoryAnalyzer/Code/assetmemoryanalyzer_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/AssetMemoryAnalyzer_precompiled.cpp Source/AssetMemoryAnalyzer_precompiled.h Include/AssetMemoryAnalyzer/AssetMemoryAnalyzerBus.h Source/AssetMemoryAnalyzer.cpp diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.cpp deleted file mode 100644 index 35211fa378..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageProcessing_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution(the "License").All use of this software is governed by the License, -*or, if provided, by the license below or the license accompanying this file.Do not -* remove or modify any license notices.This file is distributed on an "AS IS" BASIS, -*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ImageProcessing_precompiled.h" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake index 69c678877d..c7ecee12bb 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ImageProcessing_precompiled.cpp Source/ImageProcessing_precompiled.h Source/Compressors/CryTextureSquisher/CryTextureSquisher.cpp Source/Compressors/CryTextureSquisher/CryTextureSquisher.h diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.cpp deleted file mode 100644 index cb87449665..0000000000 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Atom_RHI_DX12_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ -#include diff --git a/Gems/Atom/RHI/DX12/Code/atom_rhi_dx12_private_common_files.cmake b/Gems/Atom/RHI/DX12/Code/atom_rhi_dx12_private_common_files.cmake index 3325964d17..13917b3f0d 100644 --- a/Gems/Atom/RHI/DX12/Code/atom_rhi_dx12_private_common_files.cmake +++ b/Gems/Atom/RHI/DX12/Code/atom_rhi_dx12_private_common_files.cmake @@ -11,7 +11,6 @@ set(FILES Source/RHI/Atom_RHI_DX12_precompiled.h - Source/RHI/Atom_RHI_DX12_precompiled.cpp Source/RHI/Buffer.cpp Source/RHI/Buffer.h Source/RHI/BufferPool.cpp diff --git a/Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.cpp b/Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.cpp deleted file mode 100644 index 42d5a87697..0000000000 --- a/Gems/Atom/RHI/Metal/Code/Source/Atom_RHI_Metal_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Atom_RHI_Metal_precompiled.h" diff --git a/Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake b/Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake index 3eb2579038..d678075f14 100644 --- a/Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake +++ b/Gems/Atom/RHI/Metal/Code/atom_rhi_metal_common_files.cmake @@ -10,6 +10,5 @@ # set(FILES - Source/Atom_RHI_Metal_precompiled.cpp Source/Atom_RHI_Metal_precompiled.h ) diff --git a/Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.cpp b/Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.cpp deleted file mode 100644 index 56bdaca01b..0000000000 --- a/Gems/Atom/RHI/Null/Code/Source/Atom_RHI_Null_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Atom_RHI_Null_precompiled.h" diff --git a/Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake b/Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake index f0f7fd03de..aeb34c55a6 100644 --- a/Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake +++ b/Gems/Atom/RHI/Null/Code/atom_rhi_null_common_files.cmake @@ -10,6 +10,5 @@ # set(FILES - Source/Atom_RHI_Null_precompiled.cpp Source/Atom_RHI_Null_precompiled.h ) diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.cpp deleted file mode 100644 index 65e8f51730..0000000000 --- a/Gems/Atom/RHI/Vulkan/Code/Source/Atom_RHI_Vulkan_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Atom_RHI_Vulkan_precompiled.h" diff --git a/Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake b/Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake index 83a962fb2b..717f2ff994 100644 --- a/Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake +++ b/Gems/Atom/RHI/Vulkan/Code/atom_rhi_vulkan_common_files.cmake @@ -10,6 +10,5 @@ # set(FILES - Source/Atom_RHI_Vulkan_precompiled.cpp Source/Atom_RHI_Vulkan_precompiled.h ) diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont_precompiled.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont_precompiled.cpp deleted file mode 100644 index 63f8a2bddb..0000000000 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont_precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include diff --git a/Gems/AtomLyIntegration/AtomFont/Code/atomfont_files.cmake b/Gems/AtomLyIntegration/AtomFont/Code/atomfont_files.cmake index d2b76a2d79..533fe9e527 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/atomfont_files.cmake +++ b/Gems/AtomLyIntegration/AtomFont/Code/atomfont_files.cmake @@ -33,5 +33,4 @@ set(FILES Include/AtomLyIntegration/AtomFont/AtomNullFont.h Include/AtomLyIntegration/AtomFont/resource.h Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h - Source/AtomFont_precompiled.cpp ) diff --git a/Gems/Camera/Code/Source/Camera_precompiled.cpp b/Gems/Camera/Code/Source/Camera_precompiled.cpp deleted file mode 100644 index a305cdc9df..0000000000 --- a/Gems/Camera/Code/Source/Camera_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Camera_precompiled.h" diff --git a/Gems/Camera/Code/camera_files.cmake b/Gems/Camera/Code/camera_files.cmake index f8bf93d66d..43f29435c5 100644 --- a/Gems/Camera/Code/camera_files.cmake +++ b/Gems/Camera/Code/camera_files.cmake @@ -16,6 +16,5 @@ set(FILES camera_files.cmake Source/CameraComponentController.cpp Source/CameraComponentController.h Source/CameraViewRegistrationBus.h - Source/Camera_precompiled.cpp Source/Camera_precompiled.h ) diff --git a/Gems/CameraFramework/Code/Source/CameraFramework_precompiled.cpp b/Gems/CameraFramework/Code/Source/CameraFramework_precompiled.cpp deleted file mode 100644 index e5c5926821..0000000000 --- a/Gems/CameraFramework/Code/Source/CameraFramework_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CameraFramework_precompiled.h" diff --git a/Gems/CameraFramework/Code/cameraframework_files.cmake b/Gems/CameraFramework/Code/cameraframework_files.cmake index f6571f1689..c62e7d6455 100644 --- a/Gems/CameraFramework/Code/cameraframework_files.cmake +++ b/Gems/CameraFramework/Code/cameraframework_files.cmake @@ -16,6 +16,5 @@ set(FILES Include/CameraFramework/ICameraTransformBehavior.h Source/CameraRigComponent.h Source/CameraRigComponent.cpp - Source/CameraFramework_precompiled.cpp Source/CameraFramework_precompiled.h ) diff --git a/Gems/DebugDraw/Code/Source/DebugDraw_precompiled.cpp b/Gems/DebugDraw/Code/Source/DebugDraw_precompiled.cpp deleted file mode 100644 index d5601bd1c0..0000000000 --- a/Gems/DebugDraw/Code/Source/DebugDraw_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "DebugDraw_precompiled.h" diff --git a/Gems/DebugDraw/Code/debugdraw_editor_files.cmake b/Gems/DebugDraw/Code/debugdraw_editor_files.cmake index a5adb2faac..da5e2c0870 100644 --- a/Gems/DebugDraw/Code/debugdraw_editor_files.cmake +++ b/Gems/DebugDraw/Code/debugdraw_editor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/DebugDraw_precompiled.cpp Source/DebugDraw_precompiled.h Include/DebugDraw/DebugDrawBus.h Source/DebugDrawModule.cpp diff --git a/Gems/DebugDraw/Code/debugdraw_files.cmake b/Gems/DebugDraw/Code/debugdraw_files.cmake index 4e0b115f1b..bc53fd1d26 100644 --- a/Gems/DebugDraw/Code/debugdraw_files.cmake +++ b/Gems/DebugDraw/Code/debugdraw_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/DebugDraw_precompiled.cpp Source/DebugDraw_precompiled.h Include/DebugDraw/DebugDrawBus.h Source/DebugDrawLineComponent.cpp diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLExtensions.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLExtensions.h index 731641f6aa..78ffa4ecda 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLExtensions.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLExtensions.h @@ -12,6 +12,7 @@ #pragma once +#include #include QT_FORWARD_DECLARE_CLASS(QOpenGLContext); diff --git a/Gems/EMotionFX/Code/Source/EMotionFX_precompiled.cpp b/Gems/EMotionFX/Code/Source/EMotionFX_precompiled.cpp deleted file mode 100644 index c827107a59..0000000000 --- a/Gems/EMotionFX/Code/Source/EMotionFX_precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - - -#include "EMotionFX_precompiled.h" diff --git a/Gems/EMotionFX/Code/emotionfx_editor_files.cmake b/Gems/EMotionFX/Code/emotionfx_editor_files.cmake index d8216822d4..8d88013e39 100644 --- a/Gems/EMotionFX/Code/emotionfx_editor_files.cmake +++ b/Gems/EMotionFX/Code/emotionfx_editor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/EMotionFX_precompiled.cpp Source/EMotionFX_precompiled.h ../Assets/Editor/Layouts/Layouts.qrc ../Assets/Editor/Images/Icons/Resources.qrc diff --git a/Gems/EMotionFX/Code/emotionfx_files.cmake b/Gems/EMotionFX/Code/emotionfx_files.cmake index 6650bb05be..88440f2d1d 100644 --- a/Gems/EMotionFX/Code/emotionfx_files.cmake +++ b/Gems/EMotionFX/Code/emotionfx_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/EMotionFX_precompiled.cpp Source/EMotionFX_precompiled.h Include/Integration/AnimationBus.h Include/Integration/MotionExtractionBus.h diff --git a/Gems/FastNoise/Code/Source/FastNoise_precompiled.cpp b/Gems/FastNoise/Code/Source/FastNoise_precompiled.cpp deleted file mode 100644 index 015459eeae..0000000000 --- a/Gems/FastNoise/Code/Source/FastNoise_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "FastNoise_precompiled.h" diff --git a/Gems/FastNoise/Code/fastnoise_files.cmake b/Gems/FastNoise/Code/fastnoise_files.cmake index 1846b689f7..56b7997848 100644 --- a/Gems/FastNoise/Code/fastnoise_files.cmake +++ b/Gems/FastNoise/Code/fastnoise_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/FastNoise_precompiled.cpp Source/FastNoise_precompiled.h Include/FastNoise/Ebuses/FastNoiseBus.h Include/FastNoise/Ebuses/FastNoiseGradientRequestBus.h diff --git a/Gems/Gestures/Code/Source/Gestures_precompiled.cpp b/Gems/Gestures/Code/Source/Gestures_precompiled.cpp deleted file mode 100644 index f0f3900ac9..0000000000 --- a/Gems/Gestures/Code/Source/Gestures_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Gestures_precompiled.h" diff --git a/Gems/Gestures/Code/gestures_files.cmake b/Gems/Gestures/Code/gestures_files.cmake index c4b6dec967..c94189a295 100644 --- a/Gems/Gestures/Code/gestures_files.cmake +++ b/Gems/Gestures/Code/gestures_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Gestures_precompiled.cpp Source/Gestures_precompiled.h Include/Gestures/GestureRecognizerClickOrTap.h Include/Gestures/GestureRecognizerClickOrTap.inl diff --git a/Gems/GradientSignal/Code/Source/GradientSignal_precompiled.cpp b/Gems/GradientSignal/Code/Source/GradientSignal_precompiled.cpp deleted file mode 100644 index cc70b11143..0000000000 --- a/Gems/GradientSignal/Code/Source/GradientSignal_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "GradientSignal_precompiled.h" diff --git a/Gems/GradientSignal/Code/gradientsignal_files.cmake b/Gems/GradientSignal/Code/gradientsignal_files.cmake index 1b5b16b5e0..88c6c604fe 100644 --- a/Gems/GradientSignal/Code/gradientsignal_files.cmake +++ b/Gems/GradientSignal/Code/gradientsignal_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/GradientSignal_precompiled.cpp Source/GradientSignal_precompiled.h Include/GradientSignal/GradientSampler.h Include/GradientSignal/SmoothStep.h diff --git a/Gems/GraphCanvas/Code/graphcanvas_files.cmake b/Gems/GraphCanvas/Code/graphcanvas_files.cmake index 98db1c7709..13d8fa8832 100644 --- a/Gems/GraphCanvas/Code/graphcanvas_files.cmake +++ b/Gems/GraphCanvas/Code/graphcanvas_files.cmake @@ -10,7 +10,6 @@ # set(FILES - precompiled.cpp precompiled.h Include/GraphCanvas/Widgets/RootGraphicsItem.h Include/GraphCanvas/tools.h diff --git a/Gems/GraphCanvas/Code/precompiled.cpp b/Gems/GraphCanvas/Code/precompiled.cpp deleted file mode 100644 index 51bab26696..0000000000 --- a/Gems/GraphCanvas/Code/precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "precompiled.h" - diff --git a/Gems/HttpRequestor/Code/Source/HttpRequestor_precompiled.cpp b/Gems/HttpRequestor/Code/Source/HttpRequestor_precompiled.cpp deleted file mode 100644 index 87aa3da28e..0000000000 --- a/Gems/HttpRequestor/Code/Source/HttpRequestor_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "HttpRequestor_precompiled.h" diff --git a/Gems/HttpRequestor/Code/httprequestor_files.cmake b/Gems/HttpRequestor/Code/httprequestor_files.cmake index c699e829c5..2e83237d35 100644 --- a/Gems/HttpRequestor/Code/httprequestor_files.cmake +++ b/Gems/HttpRequestor/Code/httprequestor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/HttpRequestor_precompiled.cpp Source/HttpRequestor_precompiled.h Source/HttpRequestManager.cpp Source/HttpRequestManager.h diff --git a/Gems/HttpRequestor/Code/lmbraws_unsupported_files.cmake b/Gems/HttpRequestor/Code/lmbraws_unsupported_files.cmake index bc5bbc81ca..dee0851f34 100644 --- a/Gems/HttpRequestor/Code/lmbraws_unsupported_files.cmake +++ b/Gems/HttpRequestor/Code/lmbraws_unsupported_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/HttpRequestor_precompiled.cpp Source/HttpRequestor_precompiled.h Source/ComponentStub.cpp ) diff --git a/Gems/ImGui/Code/Source/ImGui_precompiled.cpp b/Gems/ImGui/Code/Source/ImGui_precompiled.cpp deleted file mode 100644 index aa38ffff9c..0000000000 --- a/Gems/ImGui/Code/Source/ImGui_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "ImGui_precompiled.h" diff --git a/Gems/ImGui/Code/imgui_common_files.cmake b/Gems/ImGui/Code/imgui_common_files.cmake index 8ece0845d6..851cd0ccf5 100644 --- a/Gems/ImGui/Code/imgui_common_files.cmake +++ b/Gems/ImGui/Code/imgui_common_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ImGui_precompiled.cpp Source/ImGui_precompiled.h Include/ImGuiBus.h Include/ImGuiContextScope.h diff --git a/Gems/ImGui/Code/imgui_lyutils_static_files.cmake b/Gems/ImGui/Code/imgui_lyutils_static_files.cmake index 64e5ea4072..9ed0113424 100644 --- a/Gems/ImGui/Code/imgui_lyutils_static_files.cmake +++ b/Gems/ImGui/Code/imgui_lyutils_static_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ImGui_precompiled.cpp Source/ImGui_precompiled.h Include/LYImGuiUtils/HistogramContainer.h Include/LYImGuiUtils/ImGuiDrawHelpers.h diff --git a/Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.cpp b/Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.cpp deleted file mode 100644 index b865614634..0000000000 --- a/Gems/InAppPurchases/Code/Source/InAppPurchases_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or -* a third party where indicated. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "InAppPurchases_precompiled.h" diff --git a/Gems/InAppPurchases/Code/inapppurchases_files.cmake b/Gems/InAppPurchases/Code/inapppurchases_files.cmake index 7b75343af9..01a867313b 100644 --- a/Gems/InAppPurchases/Code/inapppurchases_files.cmake +++ b/Gems/InAppPurchases/Code/inapppurchases_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/InAppPurchases_precompiled.cpp Source/InAppPurchases_precompiled.h Include/InAppPurchases/InAppPurchasesBus.h Include/InAppPurchases/InAppPurchasesInterface.h diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.cpp deleted file mode 100644 index 5752d6a093..0000000000 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "LmbrCentral_precompiled.h" diff --git a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake index 9b4d01af23..d18da75507 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/LmbrCentral_precompiled.cpp Source/LmbrCentral_precompiled.h include/LmbrCentral/Ai/NavigationComponentBus.h include/LmbrCentral/Ai/NavigationAreaBus.h diff --git a/Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.cpp b/Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.cpp deleted file mode 100644 index e894c3a0f7..0000000000 --- a/Gems/LyShine/Code/Editor/UiCanvasEditor_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "UiCanvasEditor_precompiled.h" diff --git a/Gems/LyShine/Code/Source/Animation/LyShine_precompiled.cpp b/Gems/LyShine/Code/Source/Animation/LyShine_precompiled.cpp deleted file mode 100644 index 02d8df72c1..0000000000 --- a/Gems/LyShine/Code/Source/Animation/LyShine_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "LyShine_precompiled.h" diff --git a/Gems/LyShine/Code/Source/LyShine_precompiled.cpp b/Gems/LyShine/Code/Source/LyShine_precompiled.cpp deleted file mode 100644 index 02d8df72c1..0000000000 --- a/Gems/LyShine/Code/Source/LyShine_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "LyShine_precompiled.h" diff --git a/Gems/LyShine/Code/lyshine_static_files.cmake b/Gems/LyShine/Code/lyshine_static_files.cmake index 8491a66030..2435a01623 100644 --- a/Gems/LyShine/Code/lyshine_static_files.cmake +++ b/Gems/LyShine/Code/lyshine_static_files.cmake @@ -16,7 +16,6 @@ set(FILES Source/LyShine.h Source/LyShineDebug.cpp Source/LyShineDebug.h - Source/LyShine_precompiled.cpp Source/LyShine_precompiled.h Source/StringUtfUtils.h Source/UiImageComponent.cpp diff --git a/Gems/LyShine/Code/lyshine_uicanvaseditor_files.cmake b/Gems/LyShine/Code/lyshine_uicanvaseditor_files.cmake index 82fc50584c..a434ec2343 100644 --- a/Gems/LyShine/Code/lyshine_uicanvaseditor_files.cmake +++ b/Gems/LyShine/Code/lyshine_uicanvaseditor_files.cmake @@ -12,7 +12,6 @@ set(FILES Editor/LyShineEditorSystemComponent.cpp Editor/LyShineEditorSystemComponent.h - Editor/UiCanvasEditor_precompiled.cpp Editor/UiCanvasEditor_precompiled.h Editor/UiCanvasEditor.qrc Editor/Animation/UiAnimViewDialog.cpp diff --git a/Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.cpp b/Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.cpp deleted file mode 100644 index 33c6ac3831..0000000000 --- a/Gems/LyShineExamples/Code/Source/LyShineExamples_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or -* a third party where indicated. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "LyShineExamples_precompiled.h" diff --git a/Gems/LyShineExamples/Code/lyshineexamples_files.cmake b/Gems/LyShineExamples/Code/lyshineexamples_files.cmake index 08fccda4ea..c82899c374 100644 --- a/Gems/LyShineExamples/Code/lyshineexamples_files.cmake +++ b/Gems/LyShineExamples/Code/lyshineexamples_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/LyShineExamples_precompiled.cpp Source/LyShineExamples_precompiled.h Include/LyShineExamples/LyShineExamplesBus.h Include/LyShineExamples/LyShineExamplesCppExampleBus.h diff --git a/Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.cpp b/Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.cpp deleted file mode 100644 index 40dec66d87..0000000000 --- a/Gems/Maestro/Code/Source/Cinematics/Maestro_precompiled.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "Maestro_precompiled.h" diff --git a/Gems/Maestro/Code/Source/Maestro_precompiled.cpp b/Gems/Maestro/Code/Source/Maestro_precompiled.cpp deleted file mode 100644 index d0c3f18d11..0000000000 --- a/Gems/Maestro/Code/Source/Maestro_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Maestro_precompiled.h" diff --git a/Gems/Maestro/Code/maestro_static_files.cmake b/Gems/Maestro/Code/maestro_static_files.cmake index c0fb90ddca..3fd5671898 100644 --- a/Gems/Maestro/Code/maestro_static_files.cmake +++ b/Gems/Maestro/Code/maestro_static_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Maestro_precompiled.cpp Source/Maestro_precompiled.h Source/Cinematics/ShadowsSetupNode.h Source/Cinematics/ShadowsSetupNode.cpp diff --git a/Gems/MessagePopup/Code/Source/MessagePopup_precompiled.cpp b/Gems/MessagePopup/Code/Source/MessagePopup_precompiled.cpp deleted file mode 100644 index 45495b87d0..0000000000 --- a/Gems/MessagePopup/Code/Source/MessagePopup_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include "MessagePopup_precompiled.h" diff --git a/Gems/MessagePopup/Code/messagepopup_files.cmake b/Gems/MessagePopup/Code/messagepopup_files.cmake index 3c8b98378a..73a5f3f6b6 100644 --- a/Gems/MessagePopup/Code/messagepopup_files.cmake +++ b/Gems/MessagePopup/Code/messagepopup_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/MessagePopup_precompiled.cpp Source/MessagePopup_precompiled.h Include/MessagePopup/MessagePopupBus.h Source/MessagePopupSystemComponent.cpp diff --git a/Gems/Metastream/Code/Source/Metastream_precompiled.cpp b/Gems/Metastream/Code/Source/Metastream_precompiled.cpp deleted file mode 100644 index 7b4896ad9f..0000000000 --- a/Gems/Metastream/Code/Source/Metastream_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Metastream_precompiled.h" diff --git a/Gems/Metastream/Code/metastream_files.cmake b/Gems/Metastream/Code/metastream_files.cmake index c5fd0ee95b..575aa09340 100644 --- a/Gems/Metastream/Code/metastream_files.cmake +++ b/Gems/Metastream/Code/metastream_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Metastream_precompiled.cpp Source/Metastream_precompiled.h Include/Metastream/MetastreamBus.h Source/DataCache.h diff --git a/Gems/Microphone/Code/Source/Microphone_precompiled.cpp b/Gems/Microphone/Code/Source/Microphone_precompiled.cpp deleted file mode 100644 index a584ed909d..0000000000 --- a/Gems/Microphone/Code/Source/Microphone_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "Microphone_precompiled.h" diff --git a/Gems/Microphone/Code/microphone_files.cmake b/Gems/Microphone/Code/microphone_files.cmake index 1058deb13c..d32a723cfb 100644 --- a/Gems/Microphone/Code/microphone_files.cmake +++ b/Gems/Microphone/Code/microphone_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Microphone_precompiled.cpp Source/Microphone_precompiled.h Source/MicrophoneSystemComponent.cpp Source/MicrophoneSystemComponent.h diff --git a/Gems/Multiplayer/Code/Source/Multiplayer_precompiled.cpp b/Gems/Multiplayer/Code/Source/Multiplayer_precompiled.cpp deleted file mode 100644 index fa8fd7b67c..0000000000 --- a/Gems/Multiplayer/Code/Source/Multiplayer_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "Multiplayer_precompiled.h" diff --git a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake index 8d0b121735..4b175c7691 100644 --- a/Gems/Multiplayer/Code/multiplayer_debug_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_debug_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/Debug/MultiplayerDebugModule.cpp Source/Debug/MultiplayerDebugModule.h diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 73de45ba9d..9f5ca8c805 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -41,7 +41,6 @@ set(FILES Include/Multiplayer/NetworkTime/RewindableObject.inl Include/Multiplayer/Physics/PhysicsUtils.h Include/Multiplayer/ReplicationWindows/IReplicationWindow.h - Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/MultiplayerSystemComponent.cpp Source/MultiplayerSystemComponent.h diff --git a/Gems/Multiplayer/Code/multiplayer_tools_files.cmake b/Gems/Multiplayer/Code/multiplayer_tools_files.cmake index 3fef954ba6..bc0b3feeeb 100644 --- a/Gems/Multiplayer/Code/multiplayer_tools_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_tools_files.cmake @@ -11,7 +11,6 @@ set(FILES Include/Multiplayer/IMultiplayerTools.h - Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/Pipeline/NetworkPrefabProcessor.cpp Source/Pipeline/NetworkPrefabProcessor.h diff --git a/Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.cpp b/Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.cpp deleted file mode 100644 index 4b6948a654..0000000000 --- a/Gems/PhysX/Code/NumericalMethods/Source/NumericalMethods_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include diff --git a/Gems/PhysX/Code/NumericalMethods/numericalmethods_files.cmake b/Gems/PhysX/Code/NumericalMethods/numericalmethods_files.cmake index 1e7abecd31..eb96204150 100644 --- a/Gems/PhysX/Code/NumericalMethods/numericalmethods_files.cmake +++ b/Gems/PhysX/Code/NumericalMethods/numericalmethods_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/NumericalMethods_precompiled.cpp Source/NumericalMethods_precompiled.h Include/NumericalMethods/Optimization.h Include/NumericalMethods/Eigenanalysis.h diff --git a/Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.cpp b/Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.cpp deleted file mode 100644 index 04bb39a00f..0000000000 --- a/Gems/PhysX/Code/Source/PhysXUnsupported_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include diff --git a/Gems/PhysX/Code/Source/PhysX_precompiled.cpp b/Gems/PhysX/Code/Source/PhysX_precompiled.cpp deleted file mode 100644 index 1300e5b541..0000000000 --- a/Gems/PhysX/Code/Source/PhysX_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include diff --git a/Gems/PhysX/Code/physx_files.cmake b/Gems/PhysX/Code/physx_files.cmake index 6350c06e0d..24aa42d62a 100644 --- a/Gems/PhysX/Code/physx_files.cmake +++ b/Gems/PhysX/Code/physx_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/PhysX_precompiled.cpp Source/PhysX_precompiled.h Source/SystemComponent.cpp Source/SystemComponent.h diff --git a/Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.cpp b/Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.cpp deleted file mode 100644 index 4199046abd..0000000000 --- a/Gems/PhysXDebug/Code/Source/PhysXDebugUnsupported_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include diff --git a/Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.cpp b/Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.cpp deleted file mode 100644 index 2fb13c5f8a..0000000000 --- a/Gems/PhysXDebug/Code/Source/PhysXDebug_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "PhysXDebug_precompiled.h" diff --git a/Gems/PhysXDebug/Code/physxdebug_editor_files.cmake b/Gems/PhysXDebug/Code/physxdebug_editor_files.cmake index 2645795a77..460da598a0 100644 --- a/Gems/PhysXDebug/Code/physxdebug_editor_files.cmake +++ b/Gems/PhysXDebug/Code/physxdebug_editor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/PhysXDebug_precompiled.cpp Source/PhysXDebug_precompiled.h Source/EditorSystemComponent.cpp Source/EditorSystemComponent.h diff --git a/Gems/PhysXDebug/Code/physxdebug_files.cmake b/Gems/PhysXDebug/Code/physxdebug_files.cmake index 7eea56626b..2d04c8e5de 100644 --- a/Gems/PhysXDebug/Code/physxdebug_files.cmake +++ b/Gems/PhysXDebug/Code/physxdebug_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/PhysXDebug_precompiled.cpp Source/PhysXDebug_precompiled.h Include/PhysXDebug/PhysXDebugBus.h Source/Module.cpp diff --git a/Gems/PhysXDebug/Code/physxdebug_unsupported_files.cmake b/Gems/PhysXDebug/Code/physxdebug_unsupported_files.cmake index e5d7ae7e46..76649b2a91 100644 --- a/Gems/PhysXDebug/Code/physxdebug_unsupported_files.cmake +++ b/Gems/PhysXDebug/Code/physxdebug_unsupported_files.cmake @@ -11,6 +11,5 @@ set(FILES Source/ModuleUnsupported.cpp - Source/PhysXDebugUnsupported_precompiled.cpp Source/PhysXDebugUnsupported_precompiled.h ) diff --git a/Gems/ScriptCanvas/Code/Editor/precompiled.cpp b/Gems/ScriptCanvas/Code/Editor/precompiled.cpp deleted file mode 100644 index 6fdd7bdc45..0000000000 --- a/Gems/ScriptCanvas/Code/Editor/precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "precompiled.h" diff --git a/Gems/ScriptCanvas/Code/Source/precompiled.cpp b/Gems/ScriptCanvas/Code/Source/precompiled.cpp deleted file mode 100644 index 6fdd7bdc45..0000000000 --- a/Gems/ScriptCanvas/Code/Source/precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "precompiled.h" diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake index 2f1555af3d..54fd98b4ce 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Editor/precompiled.cpp Editor/precompiled.h Editor/ScriptCanvasEditorGem.cpp Editor/Settings.h diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_shared_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_shared_files.cmake index 17b62d1d3d..42b6bfed72 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_shared_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_editor_shared_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Editor/precompiled.cpp Editor/precompiled.h Editor/ScriptCanvasEditorGem.cpp Include/ScriptCanvas/ScriptCanvasGem.h diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_game_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_game_files.cmake index ead7f6d660..dfe0c6f5e3 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_game_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_game_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/precompiled.cpp Source/precompiled.h Source/ScriptCanvasGem.cpp ) diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_tests_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_tests_files.cmake index 9a877a2b42..7791c9ca48 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_tests_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_tests_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/precompiled.cpp Source/precompiled.h Tests/ScriptCanvasTest.cpp ) diff --git a/Gems/ScriptCanvasDeveloper/Code/Source/precompiled.cpp b/Gems/ScriptCanvasDeveloper/Code/Source/precompiled.cpp deleted file mode 100644 index 6fdd7bdc45..0000000000 --- a/Gems/ScriptCanvasDeveloper/Code/Source/precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "precompiled.h" diff --git a/Gems/ScriptCanvasDeveloper/Code/scriptcanvasdeveloper_gem_common_files.cmake b/Gems/ScriptCanvasDeveloper/Code/scriptcanvasdeveloper_gem_common_files.cmake index fd63448066..34de0f5910 100644 --- a/Gems/ScriptCanvasDeveloper/Code/scriptcanvasdeveloper_gem_common_files.cmake +++ b/Gems/ScriptCanvasDeveloper/Code/scriptcanvasdeveloper_gem_common_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/precompiled.cpp Source/precompiled.h Include/ScriptCanvasDeveloper/ScriptCanvasDeveloperGem.h Include/ScriptCanvasDeveloper/ScriptCanvasDeveloperComponent.h diff --git a/Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.cpp b/Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.cpp deleted file mode 100644 index 683b5507b8..0000000000 --- a/Gems/ScriptCanvasPhysics/Code/Source/ScriptCanvasPhysics_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ScriptCanvasPhysics_precompiled.h" diff --git a/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_files.cmake b/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_files.cmake index b2fdfacf67..8815d67909 100644 --- a/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_files.cmake +++ b/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ScriptCanvasPhysics_precompiled.cpp Source/ScriptCanvasPhysics_precompiled.h Source/PhysicsNodeLibrary.cpp Source/PhysicsNodeLibrary.h diff --git a/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_shared_files.cmake b/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_shared_files.cmake index 769a3db241..b7c97e99ec 100644 --- a/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_shared_files.cmake +++ b/Gems/ScriptCanvasPhysics/Code/scriptcanvas_physics_shared_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ScriptCanvasPhysics_precompiled.cpp Source/ScriptCanvasPhysics_precompiled.h Source/ScriptCanvasPhysicsModule.cpp ) diff --git a/Gems/ScriptEvents/Code/Source/precompiled.cpp b/Gems/ScriptEvents/Code/Source/precompiled.cpp deleted file mode 100644 index 6fdd7bdc45..0000000000 --- a/Gems/ScriptEvents/Code/Source/precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "precompiled.h" diff --git a/Gems/ScriptEvents/Code/scriptevents_editor_files.cmake b/Gems/ScriptEvents/Code/scriptevents_editor_files.cmake index 8fc57de0dd..c3a491d5bf 100644 --- a/Gems/ScriptEvents/Code/scriptevents_editor_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_editor_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/precompiled.cpp Source/precompiled.h Source/Editor/ScriptEventsEditorGem.cpp Source/Editor/ScriptEventsSystemEditorComponent.cpp diff --git a/Gems/ScriptEvents/Code/scriptevents_files.cmake b/Gems/ScriptEvents/Code/scriptevents_files.cmake index a79f81ab28..348ac8b1b5 100644 --- a/Gems/ScriptEvents/Code/scriptevents_files.cmake +++ b/Gems/ScriptEvents/Code/scriptevents_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/precompiled.cpp Source/precompiled.h Source/ScriptEventsGem.cpp ) diff --git a/Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.cpp b/Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.cpp deleted file mode 100644 index 85423f94c1..0000000000 --- a/Gems/ScriptedEntityTweener/Code/Source/ScriptedEntityTweener_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or -* a third party where indicated. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "ScriptedEntityTweener_precompiled.h" diff --git a/Gems/ScriptedEntityTweener/Code/scriptedentitytweener_files.cmake b/Gems/ScriptedEntityTweener/Code/scriptedentitytweener_files.cmake index b889832c16..e3d8d57e2b 100644 --- a/Gems/ScriptedEntityTweener/Code/scriptedentitytweener_files.cmake +++ b/Gems/ScriptedEntityTweener/Code/scriptedentitytweener_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/ScriptedEntityTweener_precompiled.cpp Source/ScriptedEntityTweener_precompiled.h Include/ScriptedEntityTweener/ScriptedEntityTweenerBus.h Include/ScriptedEntityTweener/ScriptedEntityTweenerEnums.h diff --git a/Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.cpp b/Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.cpp deleted file mode 100644 index 99dba85db4..0000000000 --- a/Gems/SliceFavorites/Code/Source/SliceFavorites_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "SliceFavorites_precompiled.h" diff --git a/Gems/SliceFavorites/Code/slicefavorites_files.cmake b/Gems/SliceFavorites/Code/slicefavorites_files.cmake index c0b878cbb8..06fcdc87e3 100644 --- a/Gems/SliceFavorites/Code/slicefavorites_files.cmake +++ b/Gems/SliceFavorites/Code/slicefavorites_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/SliceFavorites_precompiled.cpp Source/SliceFavorites_precompiled.h Include/SliceFavorites/SliceFavoritesBus.h Source/SliceFavoritesSystemComponent.cpp diff --git a/Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.cpp b/Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.cpp deleted file mode 100644 index 79702ea5f2..0000000000 --- a/Gems/StartingPointCamera/Code/Source/StartingPointCamera_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "StartingPointCamera_precompiled.h" diff --git a/Gems/StartingPointCamera/Code/startingpointcamera_files.cmake b/Gems/StartingPointCamera/Code/startingpointcamera_files.cmake index e0f5331e41..9f4c100f77 100644 --- a/Gems/StartingPointCamera/Code/startingpointcamera_files.cmake +++ b/Gems/StartingPointCamera/Code/startingpointcamera_files.cmake @@ -33,6 +33,5 @@ set(FILES Source/CameraTransformBehaviors/OffsetCameraPosition.cpp Source/CameraTransformBehaviors/Rotate.h Source/CameraTransformBehaviors/Rotate.cpp - Source/StartingPointCamera_precompiled.cpp Source/StartingPointCamera_precompiled.h ) diff --git a/Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.cpp b/Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.cpp deleted file mode 100644 index e4c7581b08..0000000000 --- a/Gems/StartingPointInput/Code/Source/StartingPointInput_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "StartingPointInput_precompiled.h" diff --git a/Gems/StartingPointInput/Code/startingpointinput_editor_files.cmake b/Gems/StartingPointInput/Code/startingpointinput_editor_files.cmake index b1e619c55d..fd69b6180c 100644 --- a/Gems/StartingPointInput/Code/startingpointinput_editor_files.cmake +++ b/Gems/StartingPointInput/Code/startingpointinput_editor_files.cmake @@ -24,6 +24,4 @@ set(FILES Source/InputNode.cpp Source/StartingPointInputGem.cpp Source/StartingPointInput_precompiled.h - Source/StartingPointInput_precompiled.cpp - ) diff --git a/Gems/StartingPointInput/Code/startingpointinput_files.cmake b/Gems/StartingPointInput/Code/startingpointinput_files.cmake index 2208dff6b5..c330233722 100644 --- a/Gems/StartingPointInput/Code/startingpointinput_files.cmake +++ b/Gems/StartingPointInput/Code/startingpointinput_files.cmake @@ -27,5 +27,4 @@ set(FILES Source/InputHandlerNodeable.ScriptCanvasNodeable.xml Source/InputNode.ScriptCanvasGrammar.xml Source/StartingPointInput_precompiled.h - Source/StartingPointInput_precompiled.cpp ) diff --git a/Gems/StartingPointMovement/Code/CMakeLists.txt b/Gems/StartingPointMovement/Code/CMakeLists.txt index 417dfe01ee..b9178dc839 100644 --- a/Gems/StartingPointMovement/Code/CMakeLists.txt +++ b/Gems/StartingPointMovement/Code/CMakeLists.txt @@ -9,21 +9,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -ly_add_target( - NAME StartingPointMovement.Static STATIC - NAMESPACE Gem - FILES_CMAKE - startingpointmovement_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Source - PUBLIC - Include - BUILD_DEPENDENCIES - PRIVATE - AZ::AzCore -) - ly_add_target( NAME StartingPointMovement ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem @@ -36,7 +21,6 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE - Gem::StartingPointMovement.Static AZ::AzCore AZ::AzFramework ) diff --git a/Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.cpp b/Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.cpp deleted file mode 100644 index 7027e2ede1..0000000000 --- a/Gems/StartingPointMovement/Code/Source/StartingPointMovement_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "StartingPointMovement_precompiled.h" diff --git a/Gems/StartingPointMovement/Code/startingpointmovement_files.cmake b/Gems/StartingPointMovement/Code/startingpointmovement_files.cmake deleted file mode 100644 index 21ce5801ac..0000000000 --- a/Gems/StartingPointMovement/Code/startingpointmovement_files.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - Include/StartingPointMovement/StartingPointMovementConstants.h - Include/StartingPointMovement/StartingPointMovementUtilities.h - Source/StartingPointMovement_precompiled.cpp - Source/StartingPointMovement_precompiled.h -) diff --git a/Gems/StartingPointMovement/Code/startingpointmovement_shared_files.cmake b/Gems/StartingPointMovement/Code/startingpointmovement_shared_files.cmake index f6bc7b14ea..3fec69b2fe 100644 --- a/Gems/StartingPointMovement/Code/startingpointmovement_shared_files.cmake +++ b/Gems/StartingPointMovement/Code/startingpointmovement_shared_files.cmake @@ -11,4 +11,7 @@ set(FILES Source/StartingPointMovementGem.cpp + Include/StartingPointMovement/StartingPointMovementConstants.h + Include/StartingPointMovement/StartingPointMovementUtilities.h + Source/StartingPointMovement_precompiled.h ) diff --git a/Gems/SurfaceData/Code/Source/SurfaceData_precompiled.cpp b/Gems/SurfaceData/Code/Source/SurfaceData_precompiled.cpp deleted file mode 100644 index ce5861193f..0000000000 --- a/Gems/SurfaceData/Code/Source/SurfaceData_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "SurfaceData_precompiled.h" diff --git a/Gems/SurfaceData/Code/surfacedata_files.cmake b/Gems/SurfaceData/Code/surfacedata_files.cmake index f906a12afc..20abf8d3ab 100644 --- a/Gems/SurfaceData/Code/surfacedata_files.cmake +++ b/Gems/SurfaceData/Code/surfacedata_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/SurfaceData_precompiled.cpp Source/SurfaceData_precompiled.h Include/SurfaceData/SurfaceDataConstants.h Include/SurfaceData/SurfaceDataTypes.h diff --git a/Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.cpp b/Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.cpp deleted file mode 100644 index 53e132032b..0000000000 --- a/Gems/TextureAtlas/Code/Source/TextureAtlas_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "TextureAtlas_precompiled.h" diff --git a/Gems/TextureAtlas/Code/textureatlas_files.cmake b/Gems/TextureAtlas/Code/textureatlas_files.cmake index c45c1d49a8..f96daa05d0 100644 --- a/Gems/TextureAtlas/Code/textureatlas_files.cmake +++ b/Gems/TextureAtlas/Code/textureatlas_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/TextureAtlas_precompiled.cpp Source/TextureAtlas_precompiled.h Include/TextureAtlas/TextureAtlasBus.h Include/TextureAtlas/TextureAtlasNotificationBus.h diff --git a/Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.cpp b/Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.cpp deleted file mode 100644 index aa7933d130..0000000000 --- a/Gems/TickBusOrderViewer/Code/Source/TickBusOrderViewer_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "TickBusOrderViewer_precompiled.h" diff --git a/Gems/TickBusOrderViewer/Code/tickbusorderviewer_files.cmake b/Gems/TickBusOrderViewer/Code/tickbusorderviewer_files.cmake index ceae29ebe3..a4f0b2228b 100644 --- a/Gems/TickBusOrderViewer/Code/tickbusorderviewer_files.cmake +++ b/Gems/TickBusOrderViewer/Code/tickbusorderviewer_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/TickBusOrderViewer_precompiled.cpp Source/TickBusOrderViewer_precompiled.h Include/TickBusOrderViewer/TickBusOrderViewerBus.h Source/TickBusOrderViewerSystemComponent.cpp diff --git a/Gems/Twitch/Code/Source/Twitch_precompiled.cpp b/Gems/Twitch/Code/Source/Twitch_precompiled.cpp deleted file mode 100644 index 40f10ede34..0000000000 --- a/Gems/Twitch/Code/Source/Twitch_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "Twitch_precompiled.h" diff --git a/Gems/Twitch/Code/lmbraws_unsupported_files.cmake b/Gems/Twitch/Code/lmbraws_unsupported_files.cmake index 1fb36a4871..5c98bf6b97 100644 --- a/Gems/Twitch/Code/lmbraws_unsupported_files.cmake +++ b/Gems/Twitch/Code/lmbraws_unsupported_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Twitch_precompiled.cpp Source/Twitch_precompiled.h Source/ComponentStub.cpp ) diff --git a/Gems/Twitch/Code/twitch_files.cmake b/Gems/Twitch/Code/twitch_files.cmake index cba8e44961..f06ef55371 100644 --- a/Gems/Twitch/Code/twitch_files.cmake +++ b/Gems/Twitch/Code/twitch_files.cmake @@ -14,7 +14,6 @@ set(FILES Include/Twitch/TwitchTypes.h Include/Twitch/BaseTypes.h Include/Twitch/RESTTypes.h - Source/Twitch_precompiled.cpp Source/Twitch_precompiled.h Source/TwitchSystemComponent.cpp Source/TwitchSystemComponent.h diff --git a/Gems/Vegetation/Code/Source/Vegetation_precompiled.cpp b/Gems/Vegetation/Code/Source/Vegetation_precompiled.cpp deleted file mode 100644 index c8ed8a1b9d..0000000000 --- a/Gems/Vegetation/Code/Source/Vegetation_precompiled.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "Vegetation_precompiled.h" diff --git a/Gems/Vegetation/Code/vegetation_files.cmake b/Gems/Vegetation/Code/vegetation_files.cmake index ff741902e2..abfd568862 100644 --- a/Gems/Vegetation/Code/vegetation_files.cmake +++ b/Gems/Vegetation/Code/vegetation_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/Vegetation_precompiled.cpp Source/Vegetation_precompiled.h Include/Vegetation/DescriptorListAsset.h Include/Vegetation/Descriptor.h diff --git a/Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.cpp b/Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.cpp deleted file mode 100644 index 8049f28d48..0000000000 --- a/Gems/VirtualGamepad/Code/Source/VirtualGamepad_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "VirtualGamepad_precompiled.h" diff --git a/Gems/VirtualGamepad/Code/virtualgamepad_files.cmake b/Gems/VirtualGamepad/Code/virtualgamepad_files.cmake index 8d026b7dbb..874d6252a2 100644 --- a/Gems/VirtualGamepad/Code/virtualgamepad_files.cmake +++ b/Gems/VirtualGamepad/Code/virtualgamepad_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/VirtualGamepad_precompiled.cpp Source/VirtualGamepad_precompiled.h Include/VirtualGamepad/VirtualGamepadBus.h Source/InputDeviceVirtualGamepad.cpp diff --git a/Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.cpp b/Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.cpp deleted file mode 100644 index 611ac1f0a1..0000000000 --- a/Gems/WhiteBox/Code/Source/WhiteBoxUnsupported_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include diff --git a/Gems/WhiteBox/Code/Source/WhiteBox_precompiled.cpp b/Gems/WhiteBox/Code/Source/WhiteBox_precompiled.cpp deleted file mode 100644 index 892230742f..0000000000 --- a/Gems/WhiteBox/Code/Source/WhiteBox_precompiled.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include "WhiteBox_precompiled.h" diff --git a/Gems/WhiteBox/Code/whitebox_supported_files.cmake b/Gems/WhiteBox/Code/whitebox_supported_files.cmake index 41aa4433cc..372f8cee45 100644 --- a/Gems/WhiteBox/Code/whitebox_supported_files.cmake +++ b/Gems/WhiteBox/Code/whitebox_supported_files.cmake @@ -10,7 +10,6 @@ # set(FILES - Source/WhiteBox_precompiled.cpp Source/WhiteBox_precompiled.h Include/WhiteBox/WhiteBoxBus.h Source/WhiteBoxAllocator.cpp diff --git a/Gems/WhiteBox/Code/whitebox_unsupported_files.cmake b/Gems/WhiteBox/Code/whitebox_unsupported_files.cmake index a44907e1be..3dca84c067 100644 --- a/Gems/WhiteBox/Code/whitebox_unsupported_files.cmake +++ b/Gems/WhiteBox/Code/whitebox_unsupported_files.cmake @@ -11,6 +11,5 @@ set(FILES Source/WhiteBoxModuleUnsupported.cpp - Source/WhiteBoxUnsupported_precompiled.cpp Source/WhiteBoxUnsupported_precompiled.h ) From 593b679fa3a2c2bfc393d0fee256e50f51cd3c1b Mon Sep 17 00:00:00 2001 From: Terry Michaels Date: Mon, 7 Jun 2021 18:11:56 -0500 Subject: [PATCH 146/153] Main toolbar consolidation and cleanup (#1167) * Moving menu options around * Consolidation and moving of toolbar functioanlity * Fixed non-unity build missing header * Updated camera icon to the correct one * Addressed review feedback * Addressed review feedback * Moved icons to new folder structure/naming --- .../AzQtComponents/Images/Menu/camera.svg | 9 + .../AzQtComponents/Images/Menu/debug.svg | 7 + .../AzQtComponents/Images/Menu/resolution.svg | 7 + .../AzQtComponents/Images/resources.qrc | 5 + Code/Sandbox/Editor/InfoBar.cpp | 394 ------------- Code/Sandbox/Editor/InfoBar.h | 121 ---- Code/Sandbox/Editor/InfoBar.ui | 333 ----------- Code/Sandbox/Editor/LayoutWnd.cpp | 138 ----- Code/Sandbox/Editor/LayoutWnd.h | 8 - Code/Sandbox/Editor/MainWindow.cpp | 98 ---- Code/Sandbox/Editor/MainWindow.h | 2 - Code/Sandbox/Editor/Style/Editor.qss | 14 - Code/Sandbox/Editor/ToolbarManager.cpp | 13 - Code/Sandbox/Editor/ViewportTitleDlg.cpp | 517 +++++++++++++++--- Code/Sandbox/Editor/ViewportTitleDlg.h | 95 +++- Code/Sandbox/Editor/ViewportTitleDlg.ui | 154 ++---- Code/Sandbox/Editor/editor_lib_files.cmake | 4 - 17 files changed, 597 insertions(+), 1322 deletions(-) create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/camera.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/debug.svg create mode 100644 Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/resolution.svg delete mode 100644 Code/Sandbox/Editor/InfoBar.cpp delete mode 100644 Code/Sandbox/Editor/InfoBar.h delete mode 100644 Code/Sandbox/Editor/InfoBar.ui diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/camera.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/camera.svg new file mode 100644 index 0000000000..7fa565d5b8 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/camera.svg @@ -0,0 +1,9 @@ + + + Camera + + + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/debug.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/debug.svg new file mode 100644 index 0000000000..938e4e3342 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/debug.svg @@ -0,0 +1,7 @@ + + + debug + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/resolution.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/resolution.svg new file mode 100644 index 0000000000..2434d6707d --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Menu/resolution.svg @@ -0,0 +1,7 @@ + + + resolution + + + + \ No newline at end of file diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index 7b0c6530ab..2487917f67 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -15,4 +15,9 @@ Notifications/download.svg Notifications/link.svg + + Menu/resolution.svg + Menu/debug.svg + Menu/camera.svg + diff --git a/Code/Sandbox/Editor/InfoBar.cpp b/Code/Sandbox/Editor/InfoBar.cpp deleted file mode 100644 index 14ef2e7f05..0000000000 --- a/Code/Sandbox/Editor/InfoBar.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "EditorDefs.h" - -#include "InfoBar.h" - -// Editor -#include "MainWindow.h" -#include "DisplaySettings.h" -#include "GameEngine.h" -#include "Include/ITransformManipulator.h" -#include "ActionManager.h" -#include "Settings.h" -#include "Include/IObjectManager.h" -#include "MathConversion.h" - -AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING -#include -AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - -#include - -#include - -void BeautifyEulerAngles(Vec3& v) -{ - if (v.x + v.y + v.z >= 360.0f) - { - v.x = 180.0f - v.x; - v.y = 180.0f - v.y; - v.z = 180.0f - v.z; - } -} - -///////////////////////////////////////////////////////////////////////////// -// CInfoBar dialog -CInfoBar::CInfoBar(QWidget* parent) - : QWidget(parent) - , ui(new Ui::CInfoBar) -{ - ui->setupUi(this); - - m_bSelectionChanged = false; - m_bDragMode = false; - m_prevMoveSpeed = 0; - m_currValue = Vec3(-111, +222, -333); //this wasn't initialized. I don't know what a good value is - m_oldMainVolume = 1.0f; - - GetIEditor()->RegisterNotifyListener(this); - - //audio request setup - m_oMuteAudioRequest.pData = &m_oMuteAudioRequestData; - m_oUnmuteAudioRequest.pData = &m_oUnmuteAudioRequestData; - - OnInitDialog(); - - auto comboBoxTextChanged = static_cast(&QComboBox::currentTextChanged); - connect(ui->m_moveSpeed, comboBoxTextChanged, this, &CInfoBar::OnUpdateMoveSpeedText); - connect(ui->m_moveSpeed->lineEdit(), &QLineEdit::returnPressed, this, &CInfoBar::OnSpeedComboBoxEnter); - - // Hide some buttons from the expander menu - AzQtComponents::Style::addClass(ui->m_physDoStepBtn, "expanderMenu_hide"); - AzQtComponents::Style::addClass(ui->m_physSingleStepBtn, "expanderMenu_hide"); - - connect(ui->m_physicsBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedPhysics); - connect(ui->m_physSingleStepBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedSingleStepPhys); - connect(ui->m_physDoStepBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedDoStepPhys); - connect(ui->m_syncPlayerBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedSyncplayer); - connect(ui->m_gotoPos, &QToolButton::clicked, this, &CInfoBar::OnBnClickedGotoPosition); - connect(ui->m_muteBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedMuteAudio); - connect(ui->m_vrBtn, &QToolButton::clicked, this, &CInfoBar::OnBnClickedEnableVR); - - connect(this, &CInfoBar::ActionTriggered, MainWindow::instance()->GetActionManager(), &ActionManager::ActionTriggered); - - connect(ui->m_physicsBtn, &QAbstractButton::toggled, ui->m_physicsBtn, [this](bool checked) { - ui->m_physicsBtn->setToolTip(checked ? tr("Stop Simulation (Ctrl+P)") : tr("Simulate (Ctrl+P)")); - }); - connect(ui->m_physSingleStepBtn, &QAbstractButton::toggled, ui->m_physSingleStepBtn, [this](bool checked) { - ui->m_physSingleStepBtn->setToolTip(checked ? tr("Disable Physics/AI Single-step Mode ('<' in Game Mode)") : tr("Enable Physics/AI Single-step Mode ('<' in Game Mode)")); - }); - connect(ui->m_syncPlayerBtn, &QAbstractButton::toggled, ui->m_syncPlayerBtn, [this](bool checked) { - ui->m_syncPlayerBtn->setToolTip(checked ? tr("Synchronize Player with Camera") : tr("Move Player and Camera Separately")); - }); - connect(ui->m_muteBtn, &QAbstractButton::toggled, ui->m_muteBtn, [this](bool checked) { - ui->m_muteBtn->setToolTip(checked ? tr("Un-mute Audio") : tr("Mute Audio")); - }); - connect(ui->m_vrBtn, &QAbstractButton::toggled, ui->m_vrBtn, [this](bool checked) { - ui->m_vrBtn->setToolTip(checked ? tr("Disable VR Preview") : tr("Enable VR Preview")); - }); - - ui->m_moveSpeed->setValidator(new QDoubleValidator(m_minSpeed, m_maxSpeed, m_numDecimals, ui->m_moveSpeed)); - - // Save off the move speed here since setting up the combo box can cause it to update values in the background. - float cameraMoveSpeed = gSettings.cameraMoveSpeed; - - // Populate the presets in the ComboBox - for (float presetValue : m_speedPresetValues) - { - ui->m_moveSpeed->addItem(QString().setNum(presetValue, 'f', m_numDecimals), presetValue); - } - - SetSpeedComboBox(cameraMoveSpeed); - - ui->m_moveSpeed->setInsertPolicy(QComboBox::NoInsert); - - using namespace AzToolsFramework::ComponentModeFramework; - EditorComponentModeNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); -} - -////////////////////////////////////////////////////////////////////////// -CInfoBar::~CInfoBar() -{ - using namespace AzToolsFramework::ComponentModeFramework; - EditorComponentModeNotificationBus::Handler::BusDisconnect(); - - GetIEditor()->UnregisterNotifyListener(this); - - AZ::VR::VREventBus::Handler::BusDisconnect(); -} - -////////////////////////////////////////////////////////////////////////// -void CInfoBar::OnEditorNotifyEvent(EEditorNotifyEvent event) -{ - if (event == eNotify_OnIdleUpdate) - { - IdleUpdate(); - } - else if (event == eNotify_OnBeginGameMode || event == eNotify_OnEndGameMode) - { - // Audio: determine muted state of audio - //m_bMuted = gEnv->pAudioSystem->GetMainVolume() == 0.f; - ui->m_muteBtn->setChecked(gSettings.bMuteAudio); - } - else if (event == eNotify_OnBeginLoad || event == eNotify_OnCloseScene) - { - // make sure AI/Physics is disabled on level load (CE-4229) - if (GetIEditor()->GetGameEngine()->GetSimulationMode()) - { - OnBnClickedPhysics(); - } - - ui->m_physicsBtn->setEnabled(false); - ui->m_physSingleStepBtn->setEnabled(false); - ui->m_physDoStepBtn->setEnabled(false); - } - else if (event == eNotify_OnEndLoad || event == eNotify_OnEndNewScene) - { - ui->m_physicsBtn->setEnabled(true); - ui->m_physSingleStepBtn->setEnabled(true); - ui->m_physDoStepBtn->setEnabled(true); - } - else if (event == eNotify_OnSelectionChange) - { - m_bSelectionChanged = true; - } -} - -void CInfoBar::IdleUpdate() -{ - if (!m_idleUpdateEnabled) - { - return; - } - - bool updateUI = false; - // Update Width/Height of selection rectangle. - AABB box; - GetIEditor()->GetSelectedRegion(box); - float width = box.max.x - box.min.x; - float height = box.max.y - box.min.y; - if (m_width != width || m_height != height) - { - m_width = width; - m_height = height; - updateUI = true; - } - - Vec3 marker = GetIEditor()->GetMarkerPosition(); - - int selectedEntitiesCount = 0; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( - selectedEntitiesCount, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntitiesCount); - if (selectedEntitiesCount != m_numSelected) - { - m_numSelected = selectedEntitiesCount; - updateUI = true; - } - - QString str; - if (updateUI) - { - if (m_numSelected == 0) - { - str = tr("None Selected"); - } - else if (m_numSelected == 1) - { - str = tr("1 Object Selected"); - } - else - { - str = tr("%1 Objects Selected").arg(m_numSelected); - } - - ui->m_statusText->setText(str); - m_sLastText = str; - } - - if (gSettings.cameraMoveSpeed != m_prevMoveSpeed && - !ui->m_moveSpeed->lineEdit()->hasFocus()) - { - m_prevMoveSpeed = gSettings.cameraMoveSpeed; - SetSpeedComboBox(gSettings.cameraMoveSpeed); - } - - { - bool bPhysics = GetIEditor()->GetGameEngine()->GetSimulationMode(); - if ((ui->m_physicsBtn->isChecked() && !bPhysics) || - (!ui->m_physicsBtn->isChecked() && bPhysics)) - { - ui->m_physicsBtn->setChecked(bPhysics); - } - - // Unsupported for Phyics:: atm - bool bSingleStep = false; - if (ui->m_physSingleStepBtn->isChecked() != bSingleStep) - { - ui->m_physSingleStepBtn->setChecked(bSingleStep); - } - - bool bSyncPlayer = GetIEditor()->GetGameEngine()->IsSyncPlayerPosition(); - if ((!ui->m_syncPlayerBtn->isChecked() && !bSyncPlayer) || - (ui->m_syncPlayerBtn->isChecked() && bSyncPlayer)) - { - ui->m_syncPlayerBtn->setChecked(!bSyncPlayer); - } - } - - // if our selection changed, or if our display values are out of date - if (m_bSelectionChanged) - { - m_bSelectionChanged = false; - } -} - -inline double Round(double fVal, double fStep) -{ - if (fStep > 0.f) - { - fVal = int_round(fVal / fStep) * fStep; - } - return fVal; -} - -void CInfoBar::OnUpdateMoveSpeedText(const QString& text) -{ - gSettings.cameraMoveSpeed = aznumeric_cast(Round(text.toDouble(), m_speedStep)); -} - -void CInfoBar::OnSpeedComboBoxEnter() -{ - ui->m_moveSpeed->clearFocus(); -} - -void CInfoBar::OnInitDialog() -{ - QFontMetrics metrics({}); - int width = metrics.boundingRect("-9999.99").width() * m_fieldWidthMultiplier; - - ui->m_moveSpeed->setFixedWidth(width); - - ui->m_physicsBtn->setEnabled(false); - ui->m_physSingleStepBtn->setEnabled(false); - ui->m_physDoStepBtn->setEnabled(false); - - ui->m_muteBtn->setChecked(gSettings.bMuteAudio); - Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest); - - //This is here just in case this class hasn't been created before - //a VR headset was initialized - ui->m_vrBtn->setEnabled(false); - if (AZ::VR::HMDDeviceRequestBus::GetTotalNumOfEventHandlers() != 0) - { - ui->m_vrBtn->setEnabled(true); - } - - AZ::VR::VREventBus::Handler::BusConnect(); -} - -void CInfoBar::OnHMDInitialized() -{ - ui->m_vrBtn->setEnabled(true); -} - -void CInfoBar::OnHMDShutdown() -{ - ui->m_vrBtn->setEnabled(false); -} - -void CInfoBar::OnBnClickedTerrainCollision() -{ - emit ActionTriggered(ID_TERRAIN_COLLISION); -} - -void CInfoBar::OnBnClickedPhysics() -{ - if (!ui->m_physicsBtn->isEnabled()) - { - return; - } - - bool bPhysics = GetIEditor()->GetGameEngine()->GetSimulationMode(); - ui->m_physicsBtn->setChecked(bPhysics); - emit ActionTriggered(ID_SWITCH_PHYSICS); - - if (bPhysics && ui->m_physSingleStepBtn->isChecked()) - { - OnBnClickedSingleStepPhys(); - } -} - -void CInfoBar::OnBnClickedSingleStepPhys() -{ -} - -void CInfoBar::OnBnClickedDoStepPhys() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CInfoBar::OnBnClickedSyncplayer() -{ - emit ActionTriggered(ID_GAME_SYNCPLAYER); -} - -////////////////////////////////////////////////////////////////////////// -void CInfoBar::OnBnClickedGotoPosition() -{ - emit ActionTriggered(ID_DISPLAY_GOTOPOSITION); -} - -////////////////////////////////////////////////////////////////////////// -void CInfoBar::OnBnClickedMuteAudio() -{ - gSettings.bMuteAudio = !gSettings.bMuteAudio; - - Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest); - - ui->m_muteBtn->setChecked(gSettings.bMuteAudio); -} - -void CInfoBar::OnBnClickedEnableVR() -{ - gSettings.bEnableGameModeVR = !gSettings.bEnableGameModeVR; - ui->m_vrBtn->setChecked(gSettings.bEnableGameModeVR); -} - -void CInfoBar::EnteredComponentMode(const AZStd::vector& /*componentModeTypes*/) -{ - ui->m_physicsBtn->setDisabled(true); -} - -void CInfoBar::LeftComponentMode(const AZStd::vector& /*componentModeTypes*/) -{ - ui->m_physicsBtn->setEnabled(true); -} - -void CInfoBar::SetSpeedComboBox(double value) -{ - value = AZStd::clamp(Round(value, m_speedStep), m_minSpeed, m_maxSpeed); - - int index = ui->m_moveSpeed->findData(value); - if (index != -1) - { - ui->m_moveSpeed->setCurrentIndex(index); - } - else - { - ui->m_moveSpeed->lineEdit()->setText(QString().setNum(value, 'f', m_numDecimals)); - } -} - -#include diff --git a/Code/Sandbox/Editor/InfoBar.h b/Code/Sandbox/Editor/InfoBar.h deleted file mode 100644 index 6e547d46c6..0000000000 --- a/Code/Sandbox/Editor/InfoBar.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_EDITOR_INFOBAR_H -#define CRYINCLUDE_EDITOR_INFOBAR_H - -#pragma once -// InfoBar.h : header file -// - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -///////////////////////////////////////////////////////////////////////////// -// CInfoBar dialog - -namespace Ui { - class CInfoBar; -} - -class CInfoBar - : public QWidget - , public IEditorNotifyListener - , public AZ::VR::VREventBus::Handler - , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler -{ - Q_OBJECT - - // Construction -public: - CInfoBar(QWidget* parent = nullptr); - ~CInfoBar(); - - // Toggle the mute audio button - void ToggleAudio() { OnBnClickedMuteAudio(); } - void SetSpeedComboBox(double value); - -Q_SIGNALS: - void ActionTriggered(int command); - - // Implementation -protected: - void IdleUpdate(); - virtual void OnEditorNotifyEvent(EEditorNotifyEvent event); - - virtual void OnOK() {}; - virtual void OnCancel() {}; - - void OnBnClickedSyncplayer(); - void OnBnClickedGotoPosition(); - - void OnSpeedComboBoxEnter(); - void OnUpdateMoveSpeedText(const QString&); - void OnBnClickedTerrainCollision(); - void OnBnClickedPhysics(); - void OnBnClickedSingleStepPhys(); - void OnBnClickedDoStepPhys(); - void OnBnClickedMuteAudio(); - void OnBnClickedEnableVR(); - void OnInitDialog(); - - ////////////////////////////////////////////////////////////////////////// - /// VR Event Bus Implementation - ////////////////////////////////////////////////////////////////////////// - void OnHMDInitialized() override; - void OnHMDShutdown() override; - ////////////////////////////////////////////////////////////////////////// - - // EditorComponentModeNotificationBus - void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; - void LeftComponentMode(const AZStd::vector& componentModeTypes) override; - - float m_width, m_height; - //int m_heightMapX,m_heightMapY; - double m_fieldWidthMultiplier = 1.8; - - int m_numSelected; - float m_prevMoveSpeed; - - // Speed combobox/lineEdit settings - double m_minSpeed = 0.1; - double m_maxSpeed = 100.0; - double m_speedStep = 0.1; - int m_numDecimals = 1; - - // Speed presets - float m_speedPresetValues[3] = { 0.1f, 1.0f, 10.0f }; - - bool m_bSelectionChanged; - - bool m_bDragMode; - QString m_sLastText; - - Vec3 m_lastValue; - Vec3 m_currValue; - float m_oldMainVolume; - - Audio::SAudioRequest m_oMuteAudioRequest; - Audio::SAudioManagerRequestData m_oMuteAudioRequestData; - Audio::SAudioRequest m_oUnmuteAudioRequest; - Audio::SAudioManagerRequestData m_oUnmuteAudioRequestData; - - QScopedPointer ui; - - bool m_idleUpdateEnabled = true; -}; - -#endif // CRYINCLUDE_EDITOR_INFOBAR_H diff --git a/Code/Sandbox/Editor/InfoBar.ui b/Code/Sandbox/Editor/InfoBar.ui deleted file mode 100644 index 84207629df..0000000000 --- a/Code/Sandbox/Editor/InfoBar.ui +++ /dev/null @@ -1,333 +0,0 @@ - - - CInfoBar - - - - 0 - 0 - 1600 - 27 - - - - - 0 - 0 - - - - true - - - b - - - - 0 - - - QLayout::SetFixedSize - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - No Objects Selected - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - Go to Position - - - Go to Position - - - - :/InfoBar/GotoLocation-default.svg:/InfoBar/GotoLocation-default.svg - - - - 22 - 18 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 1 - 18 - - - - - - - - Speed - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Camera Movement Speed - - - true - - - - - - - - 0 - 0 - - - - Synchronize Player with Camera - - - Synchronize Player with Camera - - - - :/InfoBar/NoPlayerSync-default.svg - :/InfoBar/NoPlayerSync-selected.svg - :/InfoBar/NoPlayerSync-default.svg - - - - 18 - 18 - - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 1 - 18 - - - - - - - - Simulate (Ctrl+P) - - - Simulate (Ctrl+P) - - - - :/InfoBar/PhysicsCol-default.svg:/InfoBar/PhysicsCol-default.svg - - - - 18 - 18 - - - - true - - - - - - - - 0 - 0 - - - - Enable Physics/AI Single-step Mode ('<' in Game Mode) - - - Enable Physics/AI Single-step Mode ('<' in Game Mode) - - - - :/InfoBar/Pause-default.svg:/InfoBar/Pause-default.svg - - - - 18 - 18 - - - - true - - - false - - - - - - - - 0 - 0 - - - - Perform a Single Physics/AI Simulation Step ('>' in Game Mode) - - - Perform a Single Physics/AI Simulation Step ('>' in Game Mode) - - - - :/InfoBar/PausePlay-default.svg:/InfoBar/PausePlay-default.svg - - - - 18 - 18 - - - - false - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 1 - 18 - - - - - - - - - 0 - 0 - - - - Mute Audio - - - Mute Audio - - - - :/InfoBar/Mute-default.svg:/InfoBar/Mute-default.svg - - - - 18 - 18 - - - - true - - - - - - - - 0 - 0 - - - - Enable VR Preview - - - Enable VR Preview - - - - :/InfoBar/VR-default.svg:/InfoBar/VR-default.svg - - - - 18 - 18 - - - - true - - - - - - - - - - diff --git a/Code/Sandbox/Editor/LayoutWnd.cpp b/Code/Sandbox/Editor/LayoutWnd.cpp index 54389f30c1..1de4d9584a 100644 --- a/Code/Sandbox/Editor/LayoutWnd.cpp +++ b/Code/Sandbox/Editor/LayoutWnd.cpp @@ -94,134 +94,12 @@ void CLayoutSplitter::CreateLayoutView(int row, int col, int id) viewPane->SetId(id); } -////////////////////////////////////////////////////////////////////////// -// InfoBarExpanderWatcher -////////////////////////////////////////////////////////////////////////// - -class InfoBarExpanderWatcher - : public QObject -{ -public: - InfoBarExpanderWatcher(QObject* parent = nullptr) - : QObject(parent) - { - } - - bool eventFilter(QObject* obj, QEvent* event) override - { - switch (event->type()) - { - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - { - if (qobject_cast(obj)) - { - auto mouseEvent = static_cast(event); - auto expansion = qobject_cast(obj); - - expansion->setPopupMode(QToolButton::InstantPopup); - auto menu = new QMenu(expansion); - - auto toolbar = qobject_cast(expansion->parentWidget()); - - auto toolWidgets = toolbar->findChildren(); - - if (toolWidgets.count() > 0) - { - for (auto toolWidget : toolWidgets) - { - if (AzQtComponents::Style::hasClass(toolWidget, "expanderMenu_hide")) - { - continue; - } - - if (auto toolButton = qobject_cast(toolWidget)) - { - if (!toolButton->isVisible()) - { - // Skip some empty buttons - if (toolButton->text().isEmpty()) - { - continue; - } - - QString plainText = QTextDocumentFragment::fromHtml(toolButton->text()).toPlainText(); - QAction* action = new QAction(plainText, menu); - - if (!toolButton->isEnabled()) - { - action->setEnabled(false); - } - - connect(action, &QAction::triggered, toolButton, &QToolButton::clicked); - - if (toolButton->isCheckable()) - { - action->setCheckable(true); - } - - action->setChecked(toolButton->isChecked()); - - menu->addAction(action); - } - } - else if (auto toolCombo = qobject_cast(toolWidget)) - { - // Add custom menu for Speed - if (toolCombo->objectName() == "m_moveSpeed") - { - double currentValue = toolCombo->lineEdit()->text().toDouble(); - - QMenu* newMenu = menu->addMenu(QString("Speed: %1").arg(currentValue)); - - double presets[] = { 0.1, 1.0, 10.0 }; - for (double preset : presets) - { - QAction* presetAction = new QAction(newMenu); - presetAction->setText(QString::number(preset)); - - connect(presetAction, &QAction::triggered, this, [preset, this]() { - if (m_infoBar) - { - m_infoBar->SetSpeedComboBox(preset); - } - }); - - newMenu->addAction(presetAction); - } - } - } - } - } - - menu->exec(mouseEvent->globalPos()); - return true; - } - - break; - } - } - - return QObject::eventFilter(obj, event); - } - - void SetInfoBar(CInfoBar* infoBar) - { - m_infoBar = infoBar; - } - -private: - CInfoBar* m_infoBar = nullptr; -}; - ////////////////////////////////////////////////////////////////////////// // CLayoutWnd ////////////////////////////////////////////////////////////////////////// CLayoutWnd::CLayoutWnd(QSettings* settings, QWidget* parent) : AzQtComponents::ToolBarArea(parent) , m_settings(settings) - , m_expanderWatcher(new InfoBarExpanderWatcher(this)) { m_bMaximized = false; m_maximizedView = 0; @@ -230,23 +108,8 @@ CLayoutWnd::CLayoutWnd(QSettings* settings, QWidget* parent) m_maximizedViewId = 0; m_infoBarSize = QSize(0, 0); - m_infoBar = new CInfoBar(this); connect(qApp, &QApplication::focusChanged, this, &CLayoutWnd::OnFocusChanged); - m_expanderWatcher->SetInfoBar(m_infoBar); - - m_infoToolBar = CreateToolBarFromWidget(m_infoBar, - Qt::BottomToolBarArea, - QStringLiteral("Info Panel")); - m_infoToolBar->setMovable(false); - m_infoToolBar->setObjectName("InfoBar"); - AzQtComponents::Style::addClass(m_infoToolBar, "DefaultSpacing"); - - if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(m_infoToolBar)) - { - expansion->installEventFilter(m_expanderWatcher); - } - setContextMenuPolicy(Qt::NoContextMenu); } @@ -415,7 +278,6 @@ void CLayoutWnd::CreateLayout(EViewLayout layout, bool bBindViewports, EViewport } QRect rcView = rect(); - rcView.setBottom(rcView.bottom() - m_infoBar->height()); // Ensure we delete our old view immediately so it can relinquish its backing ViewportContext if (m_maximizedView) diff --git a/Code/Sandbox/Editor/LayoutWnd.h b/Code/Sandbox/Editor/LayoutWnd.h index 87240cbf76..2af56f907c 100644 --- a/Code/Sandbox/Editor/LayoutWnd.h +++ b/Code/Sandbox/Editor/LayoutWnd.h @@ -20,7 +20,6 @@ #if !defined(Q_MOC_RUN) #include "Viewport.h" -#include "InfoBar.h" #include #include @@ -77,8 +76,6 @@ private: friend class CLayoutWnd; }; -class InfoBarExpanderWatcher; - /** Main layout window. */ class CLayoutWnd @@ -116,8 +113,6 @@ public: //! Switch 2D viewports. void Cycle2DViewport(); - CInfoBar& GetInfoBar() { return *m_infoBar; } - public slots: void ResetLayout(); @@ -162,11 +157,8 @@ private: // Id of maximized view pane. int m_maximizedViewId; - CInfoBar* m_infoBar; - QToolBar* m_infoToolBar; QSize m_infoBarSize; QSettings* m_settings; - InfoBarExpanderWatcher* m_expanderWatcher; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/Code/Sandbox/Editor/MainWindow.cpp b/Code/Sandbox/Editor/MainWindow.cpp index 9e983c3593..31eac05824 100644 --- a/Code/Sandbox/Editor/MainWindow.cpp +++ b/Code/Sandbox/Editor/MainWindow.cpp @@ -297,68 +297,6 @@ namespace } } -class SnapToWidget - : public QWidget -{ -public: - typedef AZStd::function SetValueCallback; - typedef AZStd::function GetValueCallback; - - SnapToWidget(QAction* defaultAction, SetValueCallback setValueCallback, GetValueCallback getValueCallback) - : m_setValueCallback(setValueCallback) - , m_getValueCallback(getValueCallback) - { - QHBoxLayout* layout = new QHBoxLayout(); - setLayout(layout); - - m_toolButton = new QToolButton(); - m_toolButton->setAutoRaise(true); - m_toolButton->setCheckable(false); - m_toolButton->setDefaultAction(defaultAction); - - m_spinBox = new AzQtComponents::DoubleSpinBox(); - - layout->addWidget(m_toolButton); - layout->addWidget(m_spinBox); - - m_spinBox->setEnabled(defaultAction->isChecked()); - m_spinBox->setMinimum(1e-2f); - - { - QSignalBlocker signalBlocker(m_spinBox); - m_spinBox->setValue(m_getValueCallback()); - } - - QObject::connect(m_spinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &SnapToWidget::OnValueChanged); - QObject::connect(defaultAction, &QAction::changed, this, &SnapToWidget::OnActionChanged); - } - - void SetIcon(QIcon icon) - { - m_toolButton->setIcon(icon); - } - -protected: - - void OnValueChanged(double value) - { - m_setValueCallback(value); - } - - void OnActionChanged() - { - m_spinBox->setEnabled(m_toolButton->isChecked()); - } - -private: - - QToolButton* m_toolButton = nullptr; - AzQtComponents::DoubleSpinBox* m_spinBox = nullptr; - - SetValueCallback m_setValueCallback; - GetValueCallback m_getValueCallback; -}; - ///////////////////////////////////////////////////////////////////////////// // MainWindow ///////////////////////////////////////////////////////////////////////////// @@ -1274,36 +1212,6 @@ void UndoRedoToolButton::Update(int count) setEnabled(count > 0); } -QWidget* MainWindow::CreateSnapToGridWidget() -{ - SnapToWidget::SetValueCallback setCallback = [](double snapStep) - { - SandboxEditor::SetGridSnappingSize(snapStep); - }; - - SnapToWidget::GetValueCallback getCallback = []() - { - return SandboxEditor::GridSnappingSize(); - }; - - return new SnapToWidget(m_actionManager->GetAction(ID_SNAP_TO_GRID), setCallback, getCallback); -} - -QWidget* MainWindow::CreateSnapToAngleWidget() -{ - SnapToWidget::SetValueCallback setCallback = [](double snapAngle) - { - SandboxEditor::SetAngleSnappingSize(snapAngle); - }; - - SnapToWidget::GetValueCallback getCallback = []() - { - return SandboxEditor::AngleSnappingSize(); - }; - - return new SnapToWidget(m_actionManager->GetAction(ID_SNAPANGLE), setCallback, getCallback); -} - bool MainWindow::IsPreview() const { return GetIEditor()->IsInPreviewMode(); @@ -2016,12 +1924,6 @@ QWidget* MainWindow::CreateToolbarWidget(int actionId) case ID_TOOLBAR_WIDGET_REDO: w = CreateUndoRedoButton(ID_REDO); break; - case ID_TOOLBAR_WIDGET_SNAP_GRID: - w = CreateSnapToGridWidget(); - break; - case ID_TOOLBAR_WIDGET_SNAP_ANGLE: - w = CreateSnapToAngleWidget(); - break; case ID_TOOLBAR_WIDGET_SPACER_RIGHT: w = CreateSpacerRightWidget(); break; diff --git a/Code/Sandbox/Editor/MainWindow.h b/Code/Sandbox/Editor/MainWindow.h index ab60b0e0d4..43600b039e 100644 --- a/Code/Sandbox/Editor/MainWindow.h +++ b/Code/Sandbox/Editor/MainWindow.h @@ -202,8 +202,6 @@ private: // AzToolsFramework::SourceControlNotificationBus::Handler: void ConnectivityStateChanged(const AzToolsFramework::SourceControlState state) override; - QWidget* CreateSnapToGridWidget(); - QWidget* CreateSnapToAngleWidget(); QWidget* CreateSpacerRightWidget(); QToolButton* CreateUndoRedoButton(int command); diff --git a/Code/Sandbox/Editor/Style/Editor.qss b/Code/Sandbox/Editor/Style/Editor.qss index fa7d67dd43..2e96c73f35 100644 --- a/Code/Sandbox/Editor/Style/Editor.qss +++ b/Code/Sandbox/Editor/Style/Editor.qss @@ -144,20 +144,6 @@ EditorWindow QToolBar border-bottom: 2px solid #111111; } -/* InfoBar (Toolbar below the main viewport) */ - -QToolBar#InfoBar -{ - qproperty-iconSize: 22px 18px; -} - -QToolBar#InfoBar AzQtComponents--VectorElement[Coordinate="X"] QLabel, -QToolBar#InfoBar AzQtComponents--VectorElement[Coordinate="Y"] QLabel, -QToolBar#InfoBar AzQtComponents--VectorElement[Coordinate="Z"] QLabel -{ - background-color: #333333; -} - DockWidgetTitleBar #DockWidgetContextMenu { qproperty-icon: url(:/Cards/img/UI20/Cards/menu_ico.svg); diff --git a/Code/Sandbox/Editor/ToolbarManager.cpp b/Code/Sandbox/Editor/ToolbarManager.cpp index 391eabae33..241b969da7 100644 --- a/Code/Sandbox/Editor/ToolbarManager.cpp +++ b/Code/Sandbox/Editor/ToolbarManager.cpp @@ -582,19 +582,6 @@ AmazonToolbar ToolbarManager::GetEditModeToolbar() const { AmazonToolbar t = AmazonToolbar("EditMode", QObject::tr("Edit Mode Toolbar")); t.SetMainToolbar(true); - t.AddAction(ID_TOOLBAR_WIDGET_UNDO, ORIGINAL_TOOLBAR_VERSION); - t.AddAction(ID_TOOLBAR_WIDGET_REDO, ORIGINAL_TOOLBAR_VERSION); - - t.AddAction(ID_TOOLBAR_SEPARATOR, ORIGINAL_TOOLBAR_VERSION); - - t.AddAction(ID_EDITMODE_MOVE, ORIGINAL_TOOLBAR_VERSION); - t.AddAction(ID_EDITMODE_ROTATE, ORIGINAL_TOOLBAR_VERSION); - t.AddAction(ID_EDITMODE_SCALE, ORIGINAL_TOOLBAR_VERSION); - - t.AddAction(ID_TOOLBAR_SEPARATOR, ORIGINAL_TOOLBAR_VERSION); - t.AddAction(ID_TOOLBAR_WIDGET_SNAP_GRID, ORIGINAL_TOOLBAR_VERSION); - t.AddAction(ID_TOOLBAR_WIDGET_SNAP_ANGLE, ORIGINAL_TOOLBAR_VERSION); - return t; } diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 5ccb83cd5b..f85aa1f06d 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -21,6 +21,8 @@ // Qt #include +#include + // CryCommon #include @@ -35,16 +37,20 @@ #include "Objects/SelectionGroup.h" #include "UsedResources.h" #include "Include/IObjectManager.h" +#include "ActionManager.h" +#include "MainWindow.h" +#include "GameEngine.h" +#include "MathConversion.h" +#include "EditorViewportSettings.h" -#include - +#include +#include AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include "ui_ViewportTitleDlg.h" AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING #endif //!defined(Q_MOC_RUN) - // CViewportTitleDlg dialog inline namespace Helpers @@ -103,7 +109,9 @@ CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) layout->addWidget(container); container->setObjectName("ViewportTitleDlgContainer"); - m_pViewPane = NULL; + m_prevMoveSpeed = 0; + + m_pViewPane = nullptr; GetIEditor()->RegisterNotifyListener(this); GetISystem()->GetISystemEventDispatcher()->RegisterListener(this); @@ -111,21 +119,176 @@ CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) LoadCustomPresets("AspectRatioPresets", "AspectRatioPreset", m_customAspectRatioPresets); LoadCustomPresets("ResPresets", "ResPreset", m_customResPresets); - OnInitDialog(); + // audio request setup + m_oMuteAudioRequest.pData = &m_oMuteAudioRequestData; + m_oUnmuteAudioRequest.pData = &m_oUnmuteAudioRequestData; - connect(m_ui->m_fovLabel, &QWidget::customContextMenuRequested, this, &CViewportTitleDlg::PopUpFOVMenu); - connect(m_ui->m_fovStaticCtrl, &QWidget::customContextMenuRequested, this, &CViewportTitleDlg::PopUpFOVMenu); - connect(m_ui->m_ratioStaticCtrl, &QWidget::customContextMenuRequested, this, &CViewportTitleDlg::PopUpAspectMenu); - connect(m_ui->m_ratioLabel, &QWidget::customContextMenuRequested, this, &CViewportTitleDlg::PopUpAspectMenu); - connect(m_ui->m_sizeStaticCtrl, &QWidget::customContextMenuRequested, this, &CViewportTitleDlg::PopUpResolutionMenu); + SetupCameraDropdownMenu(); + SetupResolutionDropdownMenu(); + SetupViewportInformationMenu(); + SetupOverflowMenu(); + + Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest); + + connect(this, &CViewportTitleDlg::ActionTriggered, MainWindow::instance()->GetActionManager(), &ActionManager::ActionTriggered); + + AZ::VR::VREventBus::Handler::BusConnect(); + + OnInitDialog(); } CViewportTitleDlg::~CViewportTitleDlg() { + AZ::VR::VREventBus::Handler::BusDisconnect(); GetISystem()->GetISystemEventDispatcher()->RemoveListener(this); GetIEditor()->UnregisterNotifyListener(this); } +void CViewportTitleDlg::SetupCameraDropdownMenu() +{ + // Setup the camera dropdown menu + QMenu* cameraMenu = new QMenu(this); + cameraMenu->addMenu(GetFovMenu()); + m_ui->m_cameraMenu->setMenu(cameraMenu); + m_ui->m_cameraMenu->setPopupMode(QToolButton::InstantPopup); + QAction* gotoPositionAction = new QAction("Go to position", cameraMenu); + connect(gotoPositionAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedGotoPosition); + cameraMenu->addAction(gotoPositionAction); + m_syncPlayerToCameraAction = new QAction("Sync camera to player", cameraMenu); + m_syncPlayerToCameraAction->setCheckable(true); + connect(m_syncPlayerToCameraAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedSyncplayer); + cameraMenu->addAction(m_syncPlayerToCameraAction); + + cameraMenu->addSeparator(); + + auto cameraSpeedActionWidget = new QWidgetAction(cameraMenu); + auto cameraSpeedContainer = new QWidget(cameraMenu); + auto cameraSpeedLabel = new QLabel(tr("Camera Speed"), cameraMenu); + m_cameraSpeed = new QComboBox(cameraMenu); + m_cameraSpeed->setEditable(true); + m_cameraSpeed->setValidator(new QDoubleValidator(m_minSpeed, m_maxSpeed, m_numDecimals, m_cameraSpeed)); + + QHBoxLayout* cameraSpeedLayout = new QHBoxLayout; + cameraSpeedLayout->addWidget(cameraSpeedLabel); + cameraSpeedLayout->addWidget(m_cameraSpeed); + cameraSpeedContainer->setLayout(cameraSpeedLayout); + cameraSpeedActionWidget->setDefaultWidget(cameraSpeedContainer); + + // Save off the move speed here since setting up the combo box can cause it to update values in the background. + float cameraMoveSpeed = gSettings.cameraMoveSpeed; + + // Populate the presets in the ComboBox + for (float presetValue : m_speedPresetValues) + { + m_cameraSpeed->addItem(QString().setNum(presetValue, 'f', m_numDecimals), presetValue); + } + + auto comboBoxTextChanged = static_cast(&QComboBox::currentTextChanged); + + SetSpeedComboBox(cameraMoveSpeed); + m_cameraSpeed->setInsertPolicy(QComboBox::NoInsert); + connect(m_cameraSpeed, comboBoxTextChanged, this, &CViewportTitleDlg::OnUpdateMoveSpeedText); + connect(m_cameraSpeed->lineEdit(), &QLineEdit::returnPressed, this, &CViewportTitleDlg::OnSpeedComboBoxEnter); + + cameraMenu->addAction(cameraSpeedActionWidget); +} + +void CViewportTitleDlg::SetupResolutionDropdownMenu() +{ + // Setup the resolution dropdown menu + QMenu* resolutionMenu = new QMenu(this); + resolutionMenu->addMenu(GetAspectMenu()); + resolutionMenu->addMenu(GetResolutionMenu()); + m_ui->m_resolutionMenu->setMenu(resolutionMenu); + m_ui->m_resolutionMenu->setPopupMode(QToolButton::InstantPopup); +} + +void CViewportTitleDlg::SetupViewportInformationMenu() +{ + // Setup the debug information button + m_ui->m_debugInformationMenu->setMenu(GetViewportInformationMenu()); + connect(m_ui->m_debugInformationMenu, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo); + m_ui->m_debugInformationMenu->setPopupMode(QToolButton::MenuButtonPopup); + +} + +void CViewportTitleDlg::SetupOverflowMenu() +{ + // Setup the overflow menu + QMenu* overFlowMenu = new QMenu(this); + m_debugHelpersAction = new QAction("Debug Helpers", overFlowMenu); + m_debugHelpersAction->setCheckable(true); + m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); + connect(m_debugHelpersAction, &QAction::triggered, this, &CViewportTitleDlg::OnToggleHelpers); + overFlowMenu->addAction(m_debugHelpersAction); + + m_audioMuteAction = new QAction("Mute Audio", overFlowMenu); + connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio); + overFlowMenu->addAction(m_audioMuteAction); + + m_enableVRAction = new QAction("Enable VR Preview", overFlowMenu); + connect(m_enableVRAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedEnableVR); + overFlowMenu->addAction(m_enableVRAction); + + overFlowMenu->addSeparator(); + + m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overFlowMenu); + connect(m_enableGridSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnGridSnappingToggled); + m_enableGridSnappingAction->setCheckable(true); + overFlowMenu->addAction(m_enableGridSnappingAction); + + m_gridSizeActionWidget = new QWidgetAction(overFlowMenu); + auto gridSizeContainer = new QWidget(overFlowMenu); + auto gridSizeLabel = new QLabel(tr("Grid Size"), overFlowMenu); + + m_gridSpinBox = new AzQtComponents::DoubleSpinBox(); + m_gridSpinBox->setValue(SandboxEditor::GridSnappingSize()); + m_gridSpinBox->setMinimum(1e-2f); + + QObject::connect( + m_gridSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnGridSpinBoxChanged); + + QHBoxLayout* gridSizeLayout = new QHBoxLayout; + gridSizeLayout->addWidget(gridSizeLabel); + gridSizeLayout->addWidget(m_gridSpinBox); + gridSizeContainer->setLayout(gridSizeLayout); + m_gridSizeActionWidget->setDefaultWidget(gridSizeContainer); + overFlowMenu->addAction(m_gridSizeActionWidget); + + overFlowMenu->addSeparator(); + + m_enableAngleSnappingAction = new QAction("Enable Grid Snapping", overFlowMenu); + connect(m_enableAngleSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnAngleSnappingToggled); + m_enableAngleSnappingAction->setCheckable(true); + overFlowMenu->addAction(m_enableAngleSnappingAction); + + m_angleSizeActionWidget = new QWidgetAction(overFlowMenu); + auto angleSizeContainer = new QWidget(overFlowMenu); + auto angleSizeLabel = new QLabel(tr("Angle Snapping"), overFlowMenu); + + m_angleSpinBox = new AzQtComponents::DoubleSpinBox(); + m_angleSpinBox->setValue(SandboxEditor::AngleSnappingSize()); + m_angleSpinBox->setMinimum(1e-2f); + + QObject::connect( + m_angleSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, + &CViewportTitleDlg::OnAngleSpinBoxChanged); + + QHBoxLayout* angleSizeLayout = new QHBoxLayout; + angleSizeLayout->addWidget(angleSizeLabel); + angleSizeLayout->addWidget(m_angleSpinBox); + angleSizeContainer->setLayout(angleSizeLayout); + m_angleSizeActionWidget->setDefaultWidget(angleSizeContainer); + overFlowMenu->addAction(m_angleSizeActionWidget); + + m_ui->m_overflowBtn->setMenu(overFlowMenu); + m_ui->m_overflowBtn->setPopupMode(QToolButton::InstantPopup); + connect(overFlowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState); + + UpdateMuteActionText(); +} + + ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane) { @@ -140,21 +303,27 @@ void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane) void CViewportTitleDlg::OnInitDialog() { m_ui->m_titleBtn->setText(m_title); - m_ui->m_sizeStaticCtrl->setText(QString()); - - m_ui->m_toggleHelpersBtn->setChecked(GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); - // Add a child parented to us that listens for r_displayInfo changes. auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this); connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo); UpdateDisplayInfo(); - connect(m_ui->m_toggleHelpersBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers); - connect(m_ui->m_toggleDisplayInfoBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo); + // This is here just in case this class hasn't been created before + // a VR headset was initialized + m_enableVRAction->setEnabled(false); + if (AZ::VR::HMDDeviceRequestBus::GetTotalNumOfEventHandlers() != 0) + { + m_enableVRAction->setEnabled(true); + } + + AZ::VR::VREventBus::Handler::BusConnect(); + + QFontMetrics metrics({}); + int width = metrics.boundingRect("-9999.99").width() * m_fieldWidthMultiplier; + + m_cameraSpeed->setFixedWidth(width); - m_ui->m_toggleHelpersBtn->setProperty("class", "big"); - m_ui->m_toggleDisplayInfoBtn->setProperty("class", "big"); } ////////////////////////////////////////////////////////////////////////// @@ -177,6 +346,80 @@ void CViewportTitleDlg::OnMaximize() void CViewportTitleDlg::OnToggleHelpers() { Helpers::ToggleHelpers(); + m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); +} + +void CViewportTitleDlg::SetNoViewportInfo() +{ + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, AZ::AtomBridge::ViewportInfoDisplayState::NoInfo); +} + +void CViewportTitleDlg::SetNormalViewportInfo() +{ + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, AZ::AtomBridge::ViewportInfoDisplayState::NormalInfo); +} + +void CViewportTitleDlg::SetFullViewportInfo() +{ + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, AZ::AtomBridge::ViewportInfoDisplayState::FullInfo); +} + +void CViewportTitleDlg::SetCompactViewportInfo() +{ + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, AZ::AtomBridge::ViewportInfoDisplayState::CompactInfo); +} + + +////////////////////////////////////////////////////////////////////////// +void CViewportTitleDlg::UpdateDisplayInfo() +{ + if (m_viewportInformationMenu == nullptr) + { + // Nothing to update, just return; + return; + } + + AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo; + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult( + state, + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState + ); + + m_noInformationAction->setChecked(false); + m_normalInformationAction->setChecked(false); + m_fullInformationAction->setChecked(false); + m_compactInformationAction->setChecked(false); + + switch (state) + { + case AZ::AtomBridge::ViewportInfoDisplayState::NormalInfo: + { + m_normalInformationAction->setChecked(true); + break; + } + case AZ::AtomBridge::ViewportInfoDisplayState::FullInfo: + { + m_fullInformationAction->setChecked(true); + break; + } + case AZ::AtomBridge::ViewportInfoDisplayState::CompactInfo: + { + m_compactInformationAction->setChecked(true); + break; + } + case AZ::AtomBridge::ViewportInfoDisplayState::NoInfo: + default: + { + m_noInformationAction->setChecked(true); + break; + } + } + + m_ui->m_debugInformationMenu->setChecked(state != AZ::AtomBridge::ViewportInfoDisplayState::NoInfo); } ////////////////////////////////////////////////////////////////////////// @@ -184,27 +427,12 @@ void CViewportTitleDlg::OnToggleDisplayInfo() { AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo; AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult( - state, - &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState - ); + state, &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState); state = aznumeric_cast( - (aznumeric_cast(state)+1) % aznumeric_cast(AZ::AtomBridge::ViewportInfoDisplayState::Invalid)); + (aznumeric_cast(state) + 1) % aznumeric_cast(AZ::AtomBridge::ViewportInfoDisplayState::Invalid)); // SetDisplayState will fire OnViewportInfoDisplayStateChanged and notify us, no need to call UpdateDisplayInfo. AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( - &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, - state - ); -} - -////////////////////////////////////////////////////////////////////////// -void CViewportTitleDlg::UpdateDisplayInfo() -{ - AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo; - AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult( - state, - &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState - ); - m_ui->m_toggleDisplayInfoBtn->setChecked(state != AZ::AtomBridge::ViewportInfoDisplayState::NoInfo); + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, state); } ////////////////////////////////////////////////////////////////////////// @@ -277,7 +505,7 @@ void CViewportTitleDlg::CreateFOVMenu() { if (!m_fovMenu) { - m_fovMenu = new QMenu(this); + m_fovMenu = new QMenu("FOV", this); } m_fovMenu->clear(); @@ -292,17 +520,6 @@ void CViewportTitleDlg::CreateFOVMenu() connect(action, &QAction::triggered, this, &CViewportTitleDlg::OnMenuFOVCustom); } -void CViewportTitleDlg::PopUpFOVMenu() -{ - if (m_pViewPane == NULL) - { - return; - } - - CreateFOVMenu(); - m_fovMenu->exec(QCursor::pos()); -} - QMenu* const CViewportTitleDlg::GetFovMenu() { CreateFOVMenu(); @@ -379,9 +596,9 @@ void CViewportTitleDlg::OnMenuAspectRatioCustom() ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::CreateAspectMenu() { - if (!m_aspectMenu) + if (m_aspectMenu == nullptr) { - m_aspectMenu = new QMenu(this); + m_aspectMenu = new QMenu("Aspect Ratio"); } m_aspectMenu->clear(); @@ -396,23 +613,48 @@ void CViewportTitleDlg::CreateAspectMenu() connect(customAction, &QAction::triggered, this, &CViewportTitleDlg::OnMenuAspectRatioCustom); } -void CViewportTitleDlg::PopUpAspectMenu() -{ - if (!m_pViewPane) - { - return; - } - - CreateAspectMenu(); - m_aspectMenu->exec(QCursor::pos()); -} - QMenu* const CViewportTitleDlg::GetAspectMenu() { CreateAspectMenu(); return m_aspectMenu; } +QMenu* const CViewportTitleDlg::GetViewportInformationMenu() +{ + CreateViewportInformationMenu(); + return m_viewportInformationMenu; +} + +void CViewportTitleDlg::CreateViewportInformationMenu() +{ + if (m_viewportInformationMenu == nullptr) + { + m_viewportInformationMenu = new QMenu("Viewport Information"); + + m_noInformationAction = new QAction(tr("None"), m_viewportInformationMenu); + m_noInformationAction->setCheckable(true); + connect(m_noInformationAction, &QAction::triggered, this, &CViewportTitleDlg::SetNoViewportInfo); + m_viewportInformationMenu->addAction(m_noInformationAction); + + m_normalInformationAction = new QAction(tr("Normal"), m_viewportInformationMenu); + m_normalInformationAction->setCheckable(true); + connect(m_normalInformationAction, &QAction::triggered, this, &CViewportTitleDlg::SetNormalViewportInfo); + m_viewportInformationMenu->addAction(m_normalInformationAction); + + m_fullInformationAction = new QAction(tr("Full"), m_viewportInformationMenu); + m_fullInformationAction->setCheckable(true); + connect(m_fullInformationAction, &QAction::triggered, this, &CViewportTitleDlg::SetFullViewportInfo); + m_viewportInformationMenu->addAction(m_fullInformationAction); + + m_compactInformationAction = new QAction(tr("Compact"), m_viewportInformationMenu); + m_compactInformationAction->setCheckable(true); + connect(m_compactInformationAction, &QAction::triggered, this, &CViewportTitleDlg::SetCompactViewportInfo); + m_viewportInformationMenu->addAction(m_compactInformationAction); + + UpdateDisplayInfo(); + } +} + void CViewportTitleDlg::AddResolutionMenus(QMenu* menu, std::function callback, const QStringList& customPresets) { static const CRenderViewport::SResolution resolutions[] = { @@ -479,7 +721,7 @@ void CViewportTitleDlg::CreateResolutionMenu() { if (!m_resolutionMenu) { - m_resolutionMenu = new QMenu(this); + m_resolutionMenu = new QMenu("Resolution"); } m_resolutionMenu->clear(); @@ -494,17 +736,6 @@ void CViewportTitleDlg::CreateResolutionMenu() connect(action, &QAction::triggered, this, &CViewportTitleDlg::OnMenuResolutionCustom); } -void CViewportTitleDlg::PopUpResolutionMenu() -{ - if (!m_pViewPane) - { - return; - } - - CreateResolutionMenu(); - m_resolutionMenu->exec(QCursor::pos()); -} - QMenu* const CViewportTitleDlg::GetResolutionMenu() { CreateResolutionMenu(); @@ -514,14 +745,14 @@ QMenu* const CViewportTitleDlg::GetResolutionMenu() ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::OnViewportSizeChanged(int width, int height) { - m_ui->m_sizeStaticCtrl->setText(QString::fromLatin1("%1 x %2").arg(width).arg(height)); + m_resolutionMenu->setTitle(QString::fromLatin1("Resolution: %1 x %2").arg(width).arg(height)); if (width != 0 && height != 0) { // Calculate greatest common divider of width & height int whGCD = gcd(width, height); - m_ui->m_ratioStaticCtrl->setText(QString::fromLatin1("%1:%2").arg(width / whGCD).arg(height / whGCD)); + m_aspectMenu->setTitle(QString::fromLatin1("Ratio: %1:%2").arg(width / whGCD).arg(height / whGCD)); } } @@ -529,9 +760,9 @@ void CViewportTitleDlg::OnViewportSizeChanged(int width, int height) void CViewportTitleDlg::OnViewportFOVChanged(float fov) { const float degFOV = RAD2DEG(fov); - if (m_ui && m_ui->m_fovStaticCtrl) + if (m_fovMenu) { - m_ui->m_fovStaticCtrl->setText(QString::fromLatin1("%1%2").arg(qRound(degFOV)).arg(QString(QByteArray::fromPercentEncoding("%C2%B0")))); + m_fovMenu->setTitle(QString::fromLatin1("FOV: %1%2").arg(qRound(degFOV)).arg(QString(QByteArray::fromPercentEncoding("%C2%B0")))); } } @@ -541,7 +772,11 @@ void CViewportTitleDlg::OnEditorNotifyEvent(EEditorNotifyEvent event) switch (event) { case eNotify_OnDisplayRenderUpdate: - m_ui->m_toggleHelpersBtn->setChecked(GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); + m_debugHelpersAction->setChecked(Helpers::IsHelpersShown()); + break; + case eNotify_OnBeginGameMode: + case eNotify_OnEndGameMode: + UpdateMuteActionText(); break; } } @@ -615,6 +850,132 @@ bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event) return QWidget::eventFilter(object, event) || consumeEvent; } +void CViewportTitleDlg::OnBnClickedSyncplayer() +{ + emit ActionTriggered(ID_GAME_SYNCPLAYER); + + bool bSyncPlayer = GetIEditor()->GetGameEngine()->IsSyncPlayerPosition(); + m_syncPlayerToCameraAction->setChecked(!bSyncPlayer); +} + +void CViewportTitleDlg::OnBnClickedGotoPosition() +{ + emit ActionTriggered(ID_DISPLAY_GOTOPOSITION); +} + +void CViewportTitleDlg::OnBnClickedMuteAudio() +{ + gSettings.bMuteAudio = !gSettings.bMuteAudio; + + Audio::AudioSystemRequestBus::Broadcast( + &Audio::AudioSystemRequestBus::Events::PushRequest, gSettings.bMuteAudio ? m_oMuteAudioRequest : m_oUnmuteAudioRequest); + + UpdateMuteActionText(); +} + +void CViewportTitleDlg::UpdateMuteActionText() +{ + m_audioMuteAction->setText(gSettings.bMuteAudio ? tr("Un-mute Audio") : tr("Mute Audio")); +} + +void CViewportTitleDlg::OnHMDInitialized() +{ + m_enableVRAction->setEnabled(true); +} + +void CViewportTitleDlg::OnHMDShutdown() +{ + m_enableVRAction->setEnabled(false); +} + +void CViewportTitleDlg::OnBnClickedEnableVR() +{ + gSettings.bEnableGameModeVR = !gSettings.bEnableGameModeVR; + + m_enableVRAction->setText(gSettings.bEnableGameModeVR ? tr("Disable VR Preview") : tr("Enable VR Preview")); +} + +inline double Round(double fVal, double fStep) +{ + if (fStep > 0.f) + { + fVal = int_round(fVal / fStep) * fStep; + } + return fVal; +} + +void CViewportTitleDlg::SetSpeedComboBox(double value) +{ + value = AZStd::clamp(Round(value, m_speedStep), m_minSpeed, m_maxSpeed); + + int index = m_cameraSpeed->findData(value); + if (index != -1) + { + m_cameraSpeed->setCurrentIndex(index); + } + else + { + m_cameraSpeed->lineEdit()->setText(QString().setNum(value, 'f', m_numDecimals)); + } +} + +void CViewportTitleDlg::OnSpeedComboBoxEnter() +{ + m_cameraSpeed->clearFocus(); +} + +void CViewportTitleDlg::OnUpdateMoveSpeedText(const QString& text) +{ + gSettings.cameraMoveSpeed = aznumeric_cast(Round(text.toDouble(), m_speedStep)); +} + +void CViewportTitleDlg::CheckForCameraSpeedUpdate() +{ + if (gSettings.cameraMoveSpeed != m_prevMoveSpeed && !m_cameraSpeed->lineEdit()->hasFocus()) + { + m_prevMoveSpeed = gSettings.cameraMoveSpeed; + SetSpeedComboBox(gSettings.cameraMoveSpeed); + } +} + +void CViewportTitleDlg::OnGridSnappingToggled() +{ + m_gridSizeActionWidget->setEnabled(m_enableGridSnappingAction->isChecked()); + MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->trigger(); +} + +void CViewportTitleDlg::OnAngleSnappingToggled() +{ + m_angleSizeActionWidget->setEnabled(m_enableAngleSnappingAction->isChecked()); + MainWindow::instance()->GetActionManager()->GetAction(ID_SNAPANGLE)->trigger(); +} + +void CViewportTitleDlg::OnGridSpinBoxChanged(double value) +{ + SandboxEditor::SetGridSnappingSize(value); +} + +void CViewportTitleDlg::OnAngleSpinBoxChanged(double value) +{ + SandboxEditor::SetAngleSnappingSize(value); +} + +void CViewportTitleDlg::UpdateOverFlowMenuState() +{ + bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->isChecked(); + { + QSignalBlocker signalBlocker(m_enableGridSnappingAction); + m_enableGridSnappingAction->setChecked(gridSnappingActive); + } + m_gridSizeActionWidget->setEnabled(gridSnappingActive); + + bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(ID_SNAPANGLE)->isChecked(); + { + QSignalBlocker signalBlocker(m_enableAngleSnappingAction); + m_enableAngleSnappingAction->setChecked(angleSnappingActive); + } + m_angleSizeActionWidget->setEnabled(angleSnappingActive); +} namespace { diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h index ce2f116d97..dd0816082a 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.h +++ b/Code/Sandbox/Editor/ViewportTitleDlg.h @@ -19,8 +19,16 @@ #include "RenderViewport.h" #include +#include + #include #include +#include +#include + +#include + +#include #endif // CViewportTitleDlg dialog @@ -42,6 +50,7 @@ class CViewportTitleDlg : public QWidget , public IEditorNotifyListener , public ISystemEventListener + , public AZ::VR::VREventBus::Handler { Q_OBJECT public: @@ -63,10 +72,15 @@ public: bool eventFilter(QObject* object, QEvent* event) override; + void SetSpeedComboBox(double value); + QMenu* const GetFovMenu(); QMenu* const GetAspectMenu(); QMenu* const GetResolutionMenu(); +Q_SIGNALS: + void ActionTriggered(int command); + protected: virtual void OnInitDialog(); @@ -75,9 +89,20 @@ protected: void OnMaximize(); void OnToggleHelpers(); - void OnToggleDisplayInfo(); void UpdateDisplayInfo(); + ////////////////////////////////////////////////////////////////////////// + /// VR Event Bus Implementation + ////////////////////////////////////////////////////////////////////////// + void OnHMDInitialized() override; + void OnHMDShutdown() override; + ////////////////////////////////////////////////////////////////////////// + + void SetupCameraDropdownMenu(); + void SetupResolutionDropdownMenu(); + void SetupViewportInformationMenu(); + void SetupOverflowMenu(); + QString m_title; CLayoutViewPane* m_pViewPane; @@ -87,22 +112,84 @@ protected: QStringList m_customFOVPresets; QStringList m_customAspectRatioPresets; + float m_prevMoveSpeed; + + // Speed combobox/lineEdit settings + double m_minSpeed = 0.1; + double m_maxSpeed = 100.0; + double m_speedStep = 0.1; + int m_numDecimals = 1; + + // Speed presets + float m_speedPresetValues[3] = { 0.1f, 1.0f, 10.0f }; + + double m_fieldWidthMultiplier = 1.8; + + void OnMenuFOVCustom(); void CreateFOVMenu(); - void PopUpFOVMenu(); void OnMenuAspectRatioCustom(); void CreateAspectMenu(); - void PopUpAspectMenu(); void OnMenuResolutionCustom(); void CreateResolutionMenu(); - void PopUpResolutionMenu(); + + void CreateViewportInformationMenu(); + QMenu* const GetViewportInformationMenu(); + void SetNoViewportInfo(); + void SetNormalViewportInfo(); + void SetFullViewportInfo(); + void SetCompactViewportInfo(); + + void OnBnClickedSyncplayer(); + void OnBnClickedGotoPosition(); + void OnBnClickedMuteAudio(); + void OnBnClickedEnableVR(); + + void UpdateMuteActionText(); + + void OnToggleDisplayInfo(); + + void OnSpeedComboBoxEnter(); + void OnUpdateMoveSpeedText(const QString&); + + void CheckForCameraSpeedUpdate(); + + void OnGridSnappingToggled(); + void OnAngleSnappingToggled(); + + void OnGridSpinBoxChanged(double value); + void OnAngleSpinBoxChanged(double value); + + void UpdateOverFlowMenuState(); QMenu* m_fovMenu = nullptr; QMenu* m_aspectMenu = nullptr; QMenu* m_resolutionMenu = nullptr; + QMenu* m_viewportInformationMenu = nullptr; + QAction* m_noInformationAction = nullptr; + QAction* m_normalInformationAction = nullptr; + QAction* m_fullInformationAction = nullptr; + QAction* m_compactInformationAction = nullptr; + QAction* m_debugHelpersAction = nullptr; + QAction* m_syncPlayerToCameraAction = nullptr; + QAction* m_audioMuteAction = nullptr; + QAction* m_enableVRAction = nullptr; + QAction* m_enableGridSnappingAction = nullptr; + QAction* m_enableAngleSnappingAction = nullptr; + QComboBox* m_cameraSpeed = nullptr; + AzQtComponents::DoubleSpinBox* m_gridSpinBox = nullptr; + AzQtComponents::DoubleSpinBox* m_angleSpinBox = nullptr; + QWidgetAction* m_gridSizeActionWidget = nullptr; + QWidgetAction* m_angleSizeActionWidget = nullptr; + + Audio::SAudioRequest m_oMuteAudioRequest; + Audio::SAudioManagerRequestData m_oMuteAudioRequestData; + Audio::SAudioRequest m_oUnmuteAudioRequest; + Audio::SAudioManagerRequestData m_oUnmuteAudioRequestData; + QScopedPointer m_ui; }; diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.ui b/Code/Sandbox/Editor/ViewportTitleDlg.ui index e7b5cce1ec..2d547bfa99 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.ui +++ b/Code/Sandbox/Editor/ViewportTitleDlg.ui @@ -61,121 +61,43 @@ - - - Qt::CustomContextMenu - - - FOV: - - + + + + :/Menu/camera.svg:/Menu/camera.svg + + + + + + + + + :/Menu/debug.svg:/Menu/debug.svg + + + + true + + + + + + + + :/Menu/resolution.svg:/Menu/resolution.svg + + + - - - - 0 - 0 - - - - Qt::CustomContextMenu - - - 120° - - - - - - - Qt::CustomContextMenu - - - Ratio: - - - - - - - - 0 - 0 - - - - - 40 - 0 - - - - Qt::CustomContextMenu - - - 000:000 - - - - - - - - 0 - 0 - - - - - 60 - 0 - - - - Qt::CustomContextMenu - - - 0000 x 0000 - - - - - - - - - - Toggle display info - - - Toggle display info - - - - :/stylesheet/img/UI20/Info.svg:/stylesheet/img/UI20/Info.svg - - - true - - - - - - - Toggle display helpers - - - Toggle display helpers - - - - :/stylesheet/img/UI20/Helpers.svg:/stylesheet/img/UI20/Helpers.svg - - - true - - + + + + :/stylesheet/img/UI20/menu-centered.svg:/stylesheet/img/UI20/menu-centered.svg + + + @@ -187,6 +109,8 @@ 1 - - + + + + diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index ebd7f89cfb..dc9d794021 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -424,10 +424,6 @@ set(FILES GotoPositionDlg.cpp GotoPositionDlg.h GotoPositionDlg.ui - InfoBar.cpp - InfoBar.qrc - InfoBar.h - InfoBar.ui LayoutConfigDialog.cpp LayoutConfigDialog.h LayoutConfigDialog.ui From d67628d88c70a89576e9e4c5f17107f2e8760fd9 Mon Sep 17 00:00:00 2001 From: guthadam Date: Mon, 7 Jun 2021 18:23:40 -0500 Subject: [PATCH 147/153] ATOM-15701 changed material inspector highlight color --- .../MaterialEditor/Code/Source/Window/MaterialEditor.qss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qss b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qss index e518d80740..506c5a2952 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qss +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditor.qss @@ -11,8 +11,8 @@ */ /* Style for visualizing property values overridden from their prefab values */ -AzToolsFramework--PropertyRowWidget[IsOverridden=true] QLabel +AzToolsFramework--PropertyRowWidget[IsOverridden="true"] QLabel { font-weight: bold; - color: #F5A623; + color: #1E70EB; } From 9373c5fd0d45ed20170f9f8f580fc80c031b6cbe Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 7 Jun 2021 18:31:57 -0700 Subject: [PATCH 148/153] Fixing xml directory race condition on incremental runs --- scripts/build/Jenkins/Jenkinsfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 1bce2988bf..4d350da55a 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -365,8 +365,11 @@ def ExportTestResults(Map options, String platform, String type, String workspac def o3deroot = "${workspace}/${ENGINE_REPOSITORY_NAME}" dir("${o3deroot}/${params.OUTPUT_DIRECTORY}") { junit testResults: "Testing/**/*.xml" - palRmDir("Testing") + palRmDir("Testing/*") } + // Recreate test runner xml directories that need to be pre generated + palMkdir("Testing/Pytest") + palMkdir("Testing/Gtest") } } From 9afe5225e6424756281127e8175c218cba1770ae Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 7 Jun 2021 18:39:03 -0700 Subject: [PATCH 149/153] removing wildcard from rmdir, not windows compatible --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 4d350da55a..e1384fcbe5 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -365,7 +365,7 @@ def ExportTestResults(Map options, String platform, String type, String workspac def o3deroot = "${workspace}/${ENGINE_REPOSITORY_NAME}" dir("${o3deroot}/${params.OUTPUT_DIRECTORY}") { junit testResults: "Testing/**/*.xml" - palRmDir("Testing/*") + palRmDir("Testing") } // Recreate test runner xml directories that need to be pre generated palMkdir("Testing/Pytest") From b2a6616a3174be80524fe03108754e7ec01bffee Mon Sep 17 00:00:00 2001 From: evanchia Date: Mon, 7 Jun 2021 18:50:21 -0700 Subject: [PATCH 150/153] fixed cwd error --- scripts/build/Jenkins/Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index e1384fcbe5..693cf31727 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -366,10 +366,10 @@ def ExportTestResults(Map options, String platform, String type, String workspac dir("${o3deroot}/${params.OUTPUT_DIRECTORY}") { junit testResults: "Testing/**/*.xml" palRmDir("Testing") + // Recreate test runner xml directories that need to be pre generated + palMkdir("Testing/Pytest") + palMkdir("Testing/Gtest") } - // Recreate test runner xml directories that need to be pre generated - palMkdir("Testing/Pytest") - palMkdir("Testing/Gtest") } } From 7ca7ad9b7280dc64c2562110cac069be1916e6ff Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 7 Jun 2021 19:50:40 -0700 Subject: [PATCH 151/153] Fix missing user_tags exception and configure gems button --- .../Resources/ProjectManager.qss | 24 +++++++++++++++++++ .../ProjectManager/Source/PythonBindings.cpp | 7 ++++-- .../Source/UpdateProjectCtrl.cpp | 4 ++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index c18d61fc24..80470591a8 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -291,6 +291,30 @@ QTabBar::tab:pressed height:50px; } +#projectSettingsTab::tab-bar > QPushButton { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #888888, stop: 1.0 #555555); + qproperty-flat: true; + margin-right:30px; + margin-bottom:12px; + margin-top:0px; + min-width:170px; + max-width:170px; + min-height:26px; + max-height:26px; + border-radius: 3px; + text-align:center; + font-size:13px; +} +#projectSettingsTab::tab-bar > QPushButton:hover { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #999999, stop: 1.0 #666666); +} +#projectSettingsTab::tab-bar > QPushButton:pressed { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #555555, stop: 1.0 #777777); +} + #projectSettingsTopFrame { background-color:#1E252F; } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 73e860112f..5e7c78d2ec 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -682,9 +682,12 @@ namespace O3DE::ProjectManager projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName); projectInfo.m_origin = Py_To_String_Optional(projectData, "origin", projectInfo.m_origin); projectInfo.m_summary = Py_To_String_Optional(projectData, "summary", projectInfo.m_summary); - for (auto tag : projectData["user_tags"]) + if (projectData.contains("user_tags")) { - projectInfo.m_userTags.append(Py_To_String(tag)); + for (auto tag : projectData["user_tags"]) + { + projectInfo.m_userTags.append(Py_To_String(tag)); + } } } catch ([[maybe_unused]] const std::exception& e) diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 3fb2d97e25..be1f0e5529 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager tabWidget->tabBar()->setObjectName("projectSettingsTabBar"); tabWidget->addTab(m_updateSettingsScreen, tr("General")); - QPushButton* gemsButton = new QPushButton(tr("Add More Gems"), this); + QPushButton* gemsButton = new QPushButton(tr("Configure Gems"), this); topBarHLayout->addWidget(gemsButton); tabWidget->setCornerWidget(gemsButton); @@ -189,7 +189,7 @@ namespace O3DE::ProjectManager { if (m_stack->currentIndex() == ScreenOrder::Gems) { - m_header->setSubTitle(QString(tr("Add More Gems to \"%1\"")).arg(m_projectInfo.m_projectName)); + m_header->setSubTitle(QString(tr("Configure Gems for \"%1\"")).arg(m_projectInfo.m_projectName)); m_nextButton->setText(tr("Confirm")); } else From 4e79e6004ceca5cb416baa9f8c780ce11636a9cb Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Tue, 8 Jun 2021 07:39:35 +0200 Subject: [PATCH 152/153] [LYN-3845] On the Actor component, click on the Animation Editor button, EMFX isn't opening (#1169) We're opening the Animation Editor now also in case no actor has been chosen yet. In this case the Animation Editor will also just be started without loading any assets. --- .../Editor/Components/EditorActorComponent.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index 7d5b7ade00..4b4685ebb1 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -435,19 +435,17 @@ namespace EMotionFX void EditorActorComponent::LaunchAnimationEditor(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType&) { + // call to open must be done before LoadCharacter + const char* panelName = EMStudio::MainWindow::GetEMotionFXPaneName(); + EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, OpenViewPane, panelName); + if (assetId.IsValid()) { AZ::Data::AssetId animgraphAssetId; - animgraphAssetId.SetInvalid(); EditorAnimGraphComponentRequestBus::EventResult(animgraphAssetId, GetEntityId(), &EditorAnimGraphComponentRequestBus::Events::GetAnimGraphAssetId); AZ::Data::AssetId motionSetAssetId; - motionSetAssetId.SetInvalid(); EditorAnimGraphComponentRequestBus::EventResult(motionSetAssetId, GetEntityId(), &EditorAnimGraphComponentRequestBus::Events::GetMotionSetAssetId); - // call to open must be done before LoadCharacter - const char* panelName = EMStudio::MainWindow::GetEMotionFXPaneName(); - EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, OpenViewPane, panelName); - EMStudio::MainWindow* mainWindow = EMStudio::GetMainWindow(); if (mainWindow) { From 863aac2cb95a5738570389be7e5881cc10541b40 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Tue, 8 Jun 2021 08:41:58 +0200 Subject: [PATCH 153/153] [LYN-3727] Actor Draw Bounds Draw Bounds & [LYN-3725] Actor Draw Skeleton Doesn't Draw Skeleton (#1168) * [LYN-3727] Actor Draw Bounds Draw Bounds & [LYN-3725] Actor Draw Skeleton Doesn't Draw Skeleton * Added skeleton, aabb and emfx debug drawing to the actor component. * Aux geom rendering is flickering as also reported in the Discord channels. Trick with using the scene notification bus did not work as the actor instance is not bound to a given scene as far as I am aware. --- .../Atom/RPI.Public/AuxGeom/AuxGeomDraw.h | 2 +- .../Code/Source/AtomActorInstance.cpp | 119 +++++++++++++++++- .../Code/Source/AtomActorInstance.h | 11 +- .../Components/EditorActorComponent.cpp | 1 + 4 files changed, 130 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h index 0e7f11e46e..525bbc1521 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h @@ -81,7 +81,7 @@ namespace AZ //! Common arguments for free polygon (point, line, Triangle) draws. struct AuxGeomDynamicDrawArguments { - const AZ::Vector3* m_verts = nullptr; //!< An array of points, 1 for each vertice. + const AZ::Vector3* m_verts = nullptr; //!< An array of points, 1 for each vertex. uint32_t m_vertCount = 0; //!< The number of vertices. const AZ::Color* m_colors; //!< An array of colors, must have either vertCount entries or 1 entry. uint32_t m_colorCount = 0; //!< The number of colors, must equal 1 or vertCount. diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 9079f639ba..532c8720b5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,8 @@ #include #include +#include +#include #include #include @@ -57,6 +60,8 @@ namespace AZ Activate(); AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId); } + + m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(m_entityId); } AtomActorInstance::~AtomActorInstance() @@ -88,7 +93,119 @@ namespace AZ AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } - AZ::Aabb AtomActorInstance:: GetWorldBounds() + void AtomActorInstance::DebugDraw(const DebugOptions& debugOptions) + { + if (m_auxGeomFeatureProcessor) + { + if (RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue()) + { + if (debugOptions.m_drawAABB) + { + const MCore::AABB emfxAabb = m_actorInstance->GetAABB(); + const AZ::Aabb azAabb = AZ::Aabb::CreateFromMinMax(emfxAabb.GetMin(), emfxAabb.GetMax()); + auxGeom->DrawAabb(azAabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); + } + + if (debugOptions.m_drawSkeleton) + { + RenderSkeleton(auxGeom.get()); + } + + if (debugOptions.m_emfxDebugDraw) + { + RenderEMFXDebugDraw(auxGeom.get()); + } + } + } + } + + void AtomActorInstance::RenderSkeleton(RPI::AuxGeomDraw* auxGeom) + { + AZ_Assert(m_actorInstance, "Valid actor instance required."); + const EMotionFX::TransformData* transformData = m_actorInstance->GetTransformData(); + const EMotionFX::Skeleton* skeleton = m_actorInstance->GetActor()->GetSkeleton(); + const EMotionFX::Pose* pose = transformData->GetCurrentPose(); + + const AZ::u32 transformCount = transformData->GetNumTransforms(); + const AZ::u32 lodLevel = m_actorInstance->GetLODLevel(); + const AZ::u32 numJoints = skeleton->GetNumNodes(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numJoints * 2); + + for (AZ::u32 jointIndex = 0; jointIndex < numJoints; ++jointIndex) + { + const EMotionFX::Node* joint = skeleton->GetNode(jointIndex); + if (!joint->GetSkeletalLODStatus(lodLevel)) + { + continue; + } + + const AZ::u32 parentIndex = joint->GetParentIndex(); + if (parentIndex == InvalidIndex32) + { + continue; + } + + const AZ::Vector3 parentPos = pose->GetWorldSpaceTransform(parentIndex).mPosition; + m_auxVertices.emplace_back(parentPos); + + const AZ::Vector3 bonePos = pose->GetWorldSpaceTransform(jointIndex).mPosition; + m_auxVertices.emplace_back(bonePos); + } + + const AZ::Color skeletonColor(0.604f, 0.804f, 0.196f, 1.0f); + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = m_auxVertices.size(); + lineArgs.m_colors = &skeletonColor; + lineArgs.m_colorCount = 1; + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + void AtomActorInstance::RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom) + { + EMotionFX::DebugDraw& debugDraw = EMotionFX::GetDebugDraw(); + debugDraw.Lock(); + EMotionFX::DebugDraw::ActorInstanceData* actorInstanceData = debugDraw.GetActorInstanceData(m_actorInstance); + actorInstanceData->Lock(); + const AZStd::vector& lines = actorInstanceData->GetLines(); + if (lines.empty()) + { + actorInstanceData->Unlock(); + debugDraw.Unlock(); + return; + } + + m_auxVertices.clear(); + m_auxVertices.reserve(lines.size() * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (const EMotionFX::DebugDraw::Line& line : actorInstanceData->GetLines()) + { + m_auxVertices.emplace_back(line.m_start); + m_auxColors.emplace_back(line.m_startColor); + m_auxVertices.emplace_back(line.m_end); + m_auxColors.emplace_back(line.m_endColor); + } + + AZ_Assert(m_auxVertices.size() == m_auxColors.size(), + "Number of vertices and number of colors need to match."); + actorInstanceData->Unlock(); + debugDraw.Unlock(); + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = m_auxVertices.size(); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = m_auxColors.size(); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + AZ::Aabb AtomActorInstance::GetWorldBounds() { return m_worldAABB; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index e05280e896..98e47e7128 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -42,6 +42,8 @@ namespace EMotionFX } namespace AZ::RPI { + class AuxGeomDraw; + class AuxGeomFeatureProcessorInterface; class Model; class Buffer; class StreamingImage; @@ -89,7 +91,7 @@ namespace AZ // RenderActorInstance overrides ... void OnTick(float timeDelta) override; void UpdateBounds() override; - void DebugDraw(const DebugOptions& debugOptions) override { AZ_UNUSED(debugOptions) }; + void DebugDraw(const DebugOptions& debugOptions) override; void SetMaterials(const EMotionFX::Integration::ActorAsset::MaterialList& materialPerLOD) override { AZ_UNUSED(materialPerLOD); }; void SetSkinningMethod(EMotionFX::Integration::SkinningMethod emfxSkinningMethod); SkinningMethod GetAtomSkinningMethod() const; @@ -177,6 +179,13 @@ namespace AZ void InitWrinkleMasks(); void UpdateWrinkleMasks(); + // Helper and debug geometry rendering + void RenderSkeleton(RPI::AuxGeomDraw* auxGeom); + void RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom); + RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr; + AZStd::vector m_auxVertices; + AZStd::vector m_auxColors; + AZStd::intrusive_ptr m_skinnedMeshInputBuffers = nullptr; AZStd::intrusive_ptr m_skinnedMeshInstance; AZ::Data::Instance m_boneTransforms = nullptr; diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index 4b4685ebb1..5c085e96f7 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -553,6 +553,7 @@ namespace EMotionFX RenderActorInstance::DebugOptions debugOptions; debugOptions.m_drawAABB = m_renderBounds; debugOptions.m_drawSkeleton = m_renderSkeleton; + debugOptions.m_emfxDebugDraw = true; m_renderActorInstance->DebugDraw(debugOptions); } }