diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index add499f080..ea5b65be7c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -36,6 +36,7 @@ ly_add_target( Gem::Atom_RPI.Edit Gem::Atom_RPI.Public Gem::Atom_RHI.Reflect + Gem::Atom_Feature_Common.Static Gem::Atom_Bootstrap.Headers ) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h new file mode 100644 index 0000000000..a96cec65b1 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +namespace AtomToolsFramework +{ + //! Interface for describing scene content that will be rendered using the PreviewRenderer + class PreviewContent + { + public: + AZ_CLASS_ALLOCATOR(PreviewContent, AZ::SystemAllocator, 0); + + PreviewContent() = default; + virtual ~PreviewContent() = default; + + //! Initiate loading of scene content, models, materials, etc + virtual void Load() = 0; + + //! Return true if content is loaded and ready to render + virtual bool IsReady() const = 0; + + //! Return true if content failed to load + virtual bool IsError() const = 0; + + //! Report any issues encountered while loading + virtual void ReportErrors() = 0; + + //! Prepare or pose content before rendering + virtual void Update() = 0; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h new file mode 100644 index 0000000000..dc03ed6715 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace AzFramework +{ + class Scene; +} + +class QPixmap; + +namespace AtomToolsFramework +{ + //! Processes requests for setting up content that gets rendered to a texture and captured to an image + class PreviewRenderer final : public PreviewerFeatureProcessorProviderBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(PreviewRenderer, AZ::SystemAllocator, 0); + + PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName); + ~PreviewRenderer(); + + struct CaptureRequest final + { + int m_size = 512; + AZStd::shared_ptr m_content; + AZStd::function m_captureFailedCallback; + AZStd::function m_captureCompleteCallback; + }; + + void AddCaptureRequest(const CaptureRequest& captureRequest); + + AZ::RPI::ScenePtr GetScene() const; + AZ::RPI::ViewPtr GetView() const; + AZ::Uuid GetEntityContextId() const; + + void ProcessCaptureRequests(); + void CancelCaptureRequest(); + void CompleteCaptureRequest(); + + void LoadContent(); + void UpdateLoadContent(); + void CancelLoadContent(); + + void PoseContent(); + + bool StartCapture(); + void EndCapture(); + + private: + //! AZ::Render::PreviewerFeatureProcessorProviderBus::Handler interface overrides... + void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const override; + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = AZ::Constants::HalfPi; + + AZ::RPI::ScenePtr m_scene; + AZStd::shared_ptr m_frameworkScene; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::RPI::ViewPtr m_view; + AZStd::vector m_passHierarchy; + AZStd::unique_ptr m_entityContext; + + //! Incoming requests are appended to this queue and processed one at a time in OnTick function. + AZStd::queue m_captureRequestQueue; + CaptureRequest m_currentCaptureRequest; + + AZStd::unique_ptr m_state; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h new file mode 100644 index 0000000000..bf68795974 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +namespace AtomToolsFramework +{ + class PreviewRenderer; + + //! PreviewRendererState decouples PreviewRenderer logic into easy-to-understand and debug pieces + class PreviewRendererState + { + public: + explicit PreviewRendererState(PreviewRenderer* renderer) + : m_renderer(renderer) + { + } + + virtual ~PreviewRendererState() = default; + + protected: + PreviewRenderer* m_renderer = {}; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h new file mode 100644 index 0000000000..fe1980b39b --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewerFeatureProcessorProviderRequests allows registering custom Feature Processors for preview image generation + class PreviewerFeatureProcessorProviderRequests : public AZ::EBusTraits + { + public: + //! Get a list of custom feature processors to register with preview image renderer + virtual void GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const = 0; + }; + + using PreviewerFeatureProcessorProviderBus = AZ::EBus; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index b407aa2b4c..69b99093f0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -25,7 +25,7 @@ namespace AtomToolsFramework { //! The RenderViewportWidget class is a Qt wrapper around an Atom viewport. - //! RenderViewportWidget renders to an internal window using RPI::ViewportContext + //! RenderViewportWidget renders to an internal window using AZ::RPI::ViewportContext //! and delegates input via its internal ViewportControllerList. //! @see AZ::RPI::ViewportContext for Atom's API for setting up class RenderViewportWidget @@ -39,7 +39,7 @@ namespace AtomToolsFramework public: //! Creates a RenderViewportWidget. //! Requires the Atom RPI to be initialized in order - //! to internally construct an RPI::ViewportContext. + //! to internally construct an AZ::RPI::ViewportContext. //! If initializeViewportContext is set to false, nothing will be displayed on-screen until InitiliazeViewportContext is called. explicit RenderViewportWidget(QWidget* parent = nullptr, bool shouldInitializeViewportContext = true); ~RenderViewportWidget(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp new file mode 100644 index 0000000000..6e47360a84 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace AtomToolsFramework +{ + PreviewRenderer::PreviewRenderer(const AZStd::string& sceneName, const AZStd::string& pipelineName) + { + PreviewerFeatureProcessorProviderBus::Handler::BusConnect(); + + m_entityContext = AZStd::make_unique(); + m_entityContext->InitContext(); + + // Create and register a scene with all required feature processors + AZStd::unordered_set featureProcessors; + PreviewerFeatureProcessorProviderBus::Broadcast( + &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); + + AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + + // Bind m_frameworkScene to the entity context's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "Failed to get scene system implementation."); + + AZ::Outcome, AZStd::string> createSceneOutcome = sceneSystem->CreateScene(sceneName); + AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); + + m_frameworkScene = createSceneOutcome.TakeValue(); + m_frameworkScene->SetSubsystem(m_scene); + m_frameworkScene->SetSubsystem(m_entityContext.get()); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = pipelineName; + pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture"; + + // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue + // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost + pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(m_renderPipeline); + m_scene->Activate(); + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + m_passHierarchy.push_back(pipelineName); + m_passHierarchy.push_back("CopyToSwapChain"); + + // Connect camera to pipeline's default view after camera entity activated + AZ::Matrix4x4 viewToClipMatrix; + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, FieldOfView, AspectRatio, NearDist, FarDist, true); + m_view = AZ::RPI::View::CreateView(AZ::Name("MainCamera"), AZ::RPI::View::UsageCamera); + m_view->SetViewToClipMatrix(viewToClipMatrix); + m_renderPipeline->SetDefaultView(m_view); + + m_state.reset(new PreviewRendererIdleState(this)); + } + + PreviewRenderer::~PreviewRenderer() + { + PreviewerFeatureProcessorProviderBus::Handler::BusDisconnect(); + + m_state.reset(); + + m_currentCaptureRequest = {}; + m_captureRequestQueue = {}; + + m_scene->Deactivate(); + m_scene->RemoveRenderPipeline(m_renderPipeline->GetId()); + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_frameworkScene->UnsetSubsystem(m_scene); + m_frameworkScene->UnsetSubsystem(m_entityContext.get()); + } + + void PreviewRenderer::AddCaptureRequest(const CaptureRequest& captureRequest) + { + m_captureRequestQueue.push(captureRequest); + } + + AZ::RPI::ScenePtr PreviewRenderer::GetScene() const + { + return m_scene; + } + + AZ::RPI::ViewPtr PreviewRenderer::GetView() const + { + return m_view; + } + + AZ::Uuid PreviewRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + + void PreviewRenderer::ProcessCaptureRequests() + { + if (!m_captureRequestQueue.empty()) + { + // pop the next request to be rendered from the queue + m_currentCaptureRequest = m_captureRequestQueue.front(); + m_captureRequestQueue.pop(); + + m_state.reset(); + m_state.reset(new PreviewRendererLoadState(this)); + } + } + + void PreviewRenderer::CancelCaptureRequest() + { + if (m_currentCaptureRequest.m_captureFailedCallback) + { + m_currentCaptureRequest.m_captureFailedCallback(); + } + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); + } + + void PreviewRenderer::CompleteCaptureRequest() + { + m_state.reset(); + m_state.reset(new PreviewRendererIdleState(this)); + } + + void PreviewRenderer::LoadContent() + { + m_currentCaptureRequest.m_content->Load(); + } + + void PreviewRenderer::UpdateLoadContent() + { + if (m_currentCaptureRequest.m_content->IsReady()) + { + m_state.reset(); + m_state.reset(new PreviewRendererCaptureState(this)); + return; + } + + if (m_currentCaptureRequest.m_content->IsError()) + { + CancelLoadContent(); + return; + } + } + + void PreviewRenderer::CancelLoadContent() + { + m_currentCaptureRequest.m_content->ReportErrors(); + CancelCaptureRequest(); + } + + void PreviewRenderer::PoseContent() + { + m_currentCaptureRequest.m_content->Update(); + } + + bool PreviewRenderer::StartCapture() + { + auto captureCompleteCallback = m_currentCaptureRequest.m_captureCompleteCallback; + auto captureFailedCallback = m_currentCaptureRequest.m_captureFailedCallback; + auto captureCallback = [captureCompleteCallback, captureFailedCallback](const AZ::RPI::AttachmentReadback::ReadbackResult& result) + { + if (result.m_dataBuffer) + { + if (captureCompleteCallback) + { + captureCompleteCallback(QPixmap::fromImage(QImage( + result.m_dataBuffer.get()->data(), result.m_imageDescriptor.m_size.m_width, + result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888))); + } + } + else + { + if (captureFailedCallback) + { + captureFailedCallback(); + } + } + }; + + if (auto renderToTexturePass = azrtti_cast(m_renderPipeline->GetRootPass().get())) + { + renderToTexturePass->ResizeOutput(m_currentCaptureRequest.m_size, m_currentCaptureRequest.m_size); + } + + m_renderPipeline->AddToRenderTickOnce(); + + bool startedCapture = false; + AZ::Render::FrameCaptureRequestBus::BroadcastResult( + startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy, + AZStd::string("Output"), captureCallback, AZ::RPI::PassAttachmentReadbackOption::Output); + return startedCapture; + } + + void PreviewRenderer::EndCapture() + { + m_currentCaptureRequest = {}; + m_renderPipeline->RemoveFromRenderTick(); + } + + void PreviewRenderer::GetRequiredFeatureProcessors(AZStd::unordered_set& featureProcessors) const + { + featureProcessors.insert({ + "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" }); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp new file mode 100644 index 0000000000..9a807b7d00 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AtomToolsFramework +{ + PreviewRendererCaptureState::PreviewRendererCaptureState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + m_renderer->PoseContent(); + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererCaptureState::~PreviewRendererCaptureState() + { + AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); + m_renderer->EndCapture(); + } + + void PreviewRendererCaptureState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + if ((m_ticksToCapture-- <= 0) && m_renderer->StartCapture()) + { + AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusDisconnect(); + } + } + + void PreviewRendererCaptureState::OnCaptureFinished( + [[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) + { + m_renderer->CompleteCaptureRequest(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h new file mode 100644 index 0000000000..e8c6357445 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererCaptureState.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererCaptureState renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished + class PreviewRendererCaptureState final + : public PreviewRendererState + , public AZ::TickBus::Handler + , public AZ::Render::FrameCaptureNotificationBus::Handler + { + public: + PreviewRendererCaptureState(PreviewRenderer* renderer); + ~PreviewRendererCaptureState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + //! AZ::Render::FrameCaptureNotificationBus::Handler overrides... + void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override; + + //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials + int m_ticksToCapture = 1; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp new file mode 100644 index 0000000000..c440bafb73 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AtomToolsFramework +{ + PreviewRendererIdleState::PreviewRendererIdleState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererIdleState::~PreviewRendererIdleState() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void PreviewRendererIdleState::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + m_renderer->ProcessCaptureRequests(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h new file mode 100644 index 0000000000..f024bd8e30 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererIdleState.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererIdleState checks whether there are any new thumbnails that need to be rendered every tick + class PreviewRendererIdleState final + : public PreviewRendererState + , public AZ::TickBus::Handler + { + public: + PreviewRendererIdleState(PreviewRenderer* renderer); + ~PreviewRendererIdleState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp new file mode 100644 index 0000000000..7e34592095 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AtomToolsFramework +{ + PreviewRendererLoadState::PreviewRendererLoadState(PreviewRenderer* renderer) + : PreviewRendererState(renderer) + { + m_renderer->LoadContent(); + AZ::TickBus::Handler::BusConnect(); + } + + PreviewRendererLoadState::~PreviewRendererLoadState() + { + AZ::TickBus::Handler::BusDisconnect(); + } + + void PreviewRendererLoadState::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) + { + if ((m_timeRemainingS += deltaTime) > TimeOutS) + { + m_renderer->CancelLoadContent(); + return; + } + + m_renderer->UpdateLoadContent(); + } +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h new file mode 100644 index 0000000000..702a01e862 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererLoadState.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +namespace AtomToolsFramework +{ + //! PreviewRendererLoadState pauses further rendering until all assets used for rendering a thumbnail have been loaded + class PreviewRendererLoadState final + : public PreviewRendererState + , public AZ::TickBus::Handler + { + public: + PreviewRendererLoadState(PreviewRenderer* renderer); + ~PreviewRendererLoadState(); + + private: + //! AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + static constexpr float TimeOutS = 5.0f; + float m_timeRemainingS = 0.0f; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 3d4bb82eec..df0dba2678 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -58,4 +58,15 @@ set(FILES Source/Window/AtomToolsMainWindow.cpp Source/Window/AtomToolsMainWindowSystemComponent.cpp Source/Window/AtomToolsMainWindowSystemComponent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewContent.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRenderer.h + Include/AtomToolsFramework/PreviewRenderer/PreviewRendererState.h + Include/AtomToolsFramework/PreviewRenderer/PreviewerFeatureProcessorProviderBus.h + Source/PreviewRenderer/PreviewRenderer.cpp + Source/PreviewRenderer/PreviewRendererIdleState.cpp + Source/PreviewRenderer/PreviewRendererIdleState.h + Source/PreviewRenderer/PreviewRendererLoadState.cpp + Source/PreviewRenderer/PreviewRendererLoadState.h + Source/PreviewRenderer/PreviewRendererCaptureState.cpp + Source/PreviewRenderer/PreviewRendererCaptureState.h ) \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h new file mode 100644 index 0000000000..30762a60ba --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +class QPixmap; + +namespace AZ +{ + namespace Render + { + //! EditorMaterialSystemComponentNotifications is an interface for handling notifications from EditorMaterialSystemComponent, like + //! being informed that material preview images are available + class EditorMaterialSystemComponentNotifications : public AZ::EBusTraits + { + public: + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + + //! Notify that a material preview image is ready + virtual void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) = 0; + }; + using EditorMaterialSystemComponentNotificationBus = AZ::EBus; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h index 47fad038b6..191f444586 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h @@ -5,20 +5,22 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include #include #include #include +#include namespace AZ { namespace Render { - //! EditorMaterialSystemComponentRequests provides an interface to communicate with MaterialEditor - class EditorMaterialSystemComponentRequests - : public AZ::EBusTraits + //! EditorMaterialSystemComponentRequests provides an interface for interacting with EditorMaterialSystemComponent, performing + //! different operations like opening the material editor, the material instance inspector, and managing material preview images + class EditorMaterialSystemComponentRequests : public AZ::EBusTraits { public: // Only a single handler is allowed @@ -31,6 +33,14 @@ namespace AZ //! Open material instance editor virtual void OpenMaterialInspector( const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Generate a material preview image + virtual void RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) = 0; + + //! Get recently rendered material preview image + virtual QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const = 0; }; using EditorMaterialSystemComponentRequestBus = AZ::EBus; } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h deleted file mode 100644 index 8030c3ae05..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include -#include - -namespace 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/EditorCommonFeaturesSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp index 896e88f4e2..1718dde5d4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.cpp @@ -6,15 +6,17 @@ * */ -#include -#include - -#include #include #include +#include +#include #include #include #include +#include +#include +#include +#include #include @@ -68,7 +70,7 @@ namespace AZ void EditorCommonFeaturesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - AZ_UNUSED(required); + required.push_back(AZ_CRC_CE("ThumbnailerService")); } void EditorCommonFeaturesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) @@ -82,24 +84,23 @@ namespace AZ void EditorCommonFeaturesSystemComponent::Activate() { - m_renderer = AZStd::make_unique(); - m_previewerFactory = AZStd::make_unique (); m_skinnedMeshDebugDisplay = AZStd::make_unique(); AzToolsFramework::EditorLevelNotificationBus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusConnect(); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } void EditorCommonFeaturesSystemComponent::Deactivate() { - AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + AzToolsFramework::EditorLevelNotificationBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler::BusDisconnect(); m_skinnedMeshDebugDisplay.reset(); - m_previewerFactory.reset(); - m_renderer.reset(); + TeardownThumbnails(); } void EditorCommonFeaturesSystemComponent::OnNewLevelCreated() @@ -191,6 +192,13 @@ namespace AZ } } + void EditorCommonFeaturesSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) + { + AZ::TickBus::QueueFunction([this](){ + SetupThumbnails(); + }); + } + const AzToolsFramework::AssetBrowser::PreviewerFactory* EditorCommonFeaturesSystemComponent::GetPreviewerFactory( const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const { @@ -199,7 +207,33 @@ namespace AZ void EditorCommonFeaturesSystemComponent::OnApplicationAboutToStop() { + TeardownThumbnails(); + } + + void EditorCommonFeaturesSystemComponent::SetupThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(SharedThumbnailCache), + ThumbnailContext::DefaultContext); + + m_renderer = AZStd::make_unique(); + m_previewerFactory = AZStd::make_unique(); + } + + void EditorCommonFeaturesSystemComponent::TeardownThumbnails() + { + using namespace AzToolsFramework::Thumbnailer; + using namespace LyIntegration; + + ThumbnailerRequestsBus::Broadcast( + &ThumbnailerRequests::UnregisterThumbnailProvider, SharedThumbnailCache::ProviderName, + ThumbnailContext::DefaultContext); + m_renderer.reset(); + m_previewerFactory.reset(); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h index 2560bf7e11..8021770873 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/EditorCommonFeaturesSystemComponent.h @@ -11,10 +11,10 @@ #include #include #include -#include #include -#include -#include +#include +#include +#include namespace AZ { @@ -28,6 +28,7 @@ namespace AZ , public AzToolsFramework::EditorLevelNotificationBus::Handler , public AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , public AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler + , public AzFramework::AssetCatalogEventBus::Handler , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: @@ -53,15 +54,23 @@ namespace AZ void OnNewLevelCreated() override; // SliceEditorEntityOwnershipServiceBus overrides ... - void OnSliceInstantiated(const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; + void OnSliceInstantiated( + const AZ::Data::AssetId&, AZ::SliceComponent::SliceInstanceAddress&, const AzFramework::SliceInstantiationTicket&) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override; + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + // AzToolsFramework::AssetBrowser::PreviewerRequestBus::Handler overrides... - const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; + const AzToolsFramework::AssetBrowser::PreviewerFactory* GetPreviewerFactory( + const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const override; // AzFramework::ApplicationLifecycleEvents overrides... void OnApplicationAboutToStop() override; + void SetupThumbnails(); + void TeardownThumbnails(); + private: AZStd::unique_ptr m_skinnedMeshDebugDisplay; @@ -69,8 +78,8 @@ namespace AZ AZStd::string m_atomLevelDefaultAssetPath{ "LevelAssets/default.slice" }; float m_envProbeHeight{ 200.0f }; - AZStd::unique_ptr m_renderer; - AZStd::unique_ptr m_previewerFactory; + AZStd::unique_ptr m_renderer; + AZStd::unique_ptr m_previewerFactory; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 8e5e7e2345..a3ae61b14b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -148,11 +148,13 @@ namespace AZ BaseClass::Activate(); MaterialReceiverNotificationBus::Handler::BusConnect(GetEntityId()); MaterialComponentNotificationBus::Handler::BusConnect(GetEntityId()); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); UpdateMaterialSlots(); } void EditorMaterialComponent::Deactivate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialReceiverNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); BaseClass::Deactivate(); @@ -260,6 +262,18 @@ namespace AZ } } + void EditorMaterialComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + if (entityId == GetEntityId()) + { + AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( + &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues); + } + } + AZ::u32 EditorMaterialComponent::OnConfigurationChanged() { return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h index f8895d994f..ce21ae82ac 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -21,8 +22,9 @@ namespace AZ //! In-editor material component for displaying and editing material assignments. class EditorMaterialComponent final : public EditorRenderComponentAdapter - , private MaterialReceiverNotificationBus::Handler - , private MaterialComponentNotificationBus::Handler + , public MaterialReceiverNotificationBus::Handler + , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { public: using BaseClass = EditorRenderComponentAdapter; @@ -52,6 +54,10 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialInstanceCreated(const MaterialAssignment& materialAssignment) override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) override; + // Regenerates the editor component material slots based on the material and // LOD mapping from the model or other consumer of materials. // If any corresponding material assignments are found in the component diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 815f14aba7..b6875e2e9c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -23,10 +23,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -49,29 +45,18 @@ namespace AZ MaterialPropertyInspector::MaterialPropertyInspector(QWidget* parent) : AtomToolsFramework::InspectorWidget(parent) { - // Create the menu button - QToolButton* menuButton = new QToolButton(this); - menuButton->setAutoRaise(true); - menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); - menuButton->setVisible(true); - QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); - AddHeading(menuButton); - - m_messageLabel = new QLabel(this); - m_messageLabel->setWordWrap(true); - m_messageLabel->setVisible(true); - m_messageLabel->setAlignment(Qt::AlignCenter); - m_messageLabel->setText(tr("Material not available")); - AddHeading(m_messageLabel); - + CreateHeading(); + AZ::TickBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); } MaterialPropertyInspector::~MaterialPropertyInspector() { AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); - AZ::EntitySystemBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); + AZ::EntitySystemBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); MaterialComponentNotificationBus::Handler::BusDisconnect(); } @@ -140,7 +125,7 @@ namespace AZ } Populate(); - m_messageLabel->setVisible(false); + LoadOverridesFromEntity(); return true; } @@ -152,8 +137,9 @@ namespace AZ m_dirtyPropertyFlags.set(); m_editorFunctors = {}; m_internalEditNotification = {}; - m_messageLabel->setVisible(true); - m_messageLabel->setText(tr("Material not available")); + m_updateUI = {}; + m_updatePreview = {}; + UpdateHeading(); } bool MaterialPropertyInspector::IsLoaded() const @@ -168,49 +154,63 @@ namespace AZ m_dirtyPropertyFlags.set(); m_internalEditNotification = {}; - AZ::TickBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); } - void MaterialPropertyInspector::AddDetailsGroup() + void MaterialPropertyInspector::CreateHeading() { - const AZStd::string& groupName = "Details"; - const AZStd::string& groupDisplayName = "Details"; - const AZStd::string& groupDescription = ""; + // Create the menu button + QToolButton* menuButton = new QToolButton(this); + menuButton->setAutoRaise(true); + menuButton->setIcon(QIcon(":/Cards/img/UI20/Cards/menu_ico.svg")); + menuButton->setVisible(true); + QObject::connect(menuButton, &QToolButton::clicked, this, [this]() { OpenMenu(); }); + AddHeading(menuButton); - auto propertyGroupContainer = new QWidget(this); - propertyGroupContainer->setLayout(new QHBoxLayout()); + m_overviewImage = new QLabel(this); + m_overviewImage->setFixedSize(QSize(120, 120)); + m_overviewImage->setScaledContents(true); + m_overviewImage->setVisible(false); - AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey = - MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, m_editData.m_materialAssetId); - auto thumbnailWidget = new AzToolsFramework::Thumbnailer::ThumbnailWidget(this); - thumbnailWidget->setFixedSize(QSize(120, 120)); - thumbnailWidget->setVisible(true); - thumbnailWidget->SetThumbnailKey(thumbnailKey, AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); - propertyGroupContainer->layout()->addWidget(thumbnailWidget); - - auto materialInfoWidget = new QLabel(this); + m_overviewText = new QLabel(this); QSizePolicy sizePolicy1(QSizePolicy::Ignored, QSizePolicy::Preferred); sizePolicy1.setHorizontalStretch(0); sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(materialInfoWidget->sizePolicy().hasHeightForWidth()); - materialInfoWidget->setSizePolicy(sizePolicy1); - materialInfoWidget->setMinimumSize(QSize(0, 0)); - materialInfoWidget->setMaximumSize(QSize(16777215, 16777215)); - materialInfoWidget->setTextFormat(Qt::AutoText); - materialInfoWidget->setScaledContents(false); - materialInfoWidget->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - materialInfoWidget->setWordWrap(true); + sizePolicy1.setHeightForWidth(m_overviewText->sizePolicy().hasHeightForWidth()); + m_overviewText->setSizePolicy(sizePolicy1); + m_overviewText->setMinimumSize(QSize(0, 0)); + m_overviewText->setMaximumSize(QSize(16777215, 16777215)); + m_overviewText->setTextFormat(Qt::AutoText); + m_overviewText->setScaledContents(false); + m_overviewText->setWordWrap(true); + m_overviewText->setVisible(true); + + auto overviewContainer = new QWidget(this); + overviewContainer->setLayout(new QHBoxLayout()); + overviewContainer->layout()->addWidget(m_overviewImage); + overviewContainer->layout()->addWidget(m_overviewText); + AddHeading(overviewContainer); + } + + void MaterialPropertyInspector::UpdateHeading() + { + if (!IsLoaded()) + { + m_overviewText->setText(tr("Material not available")); + m_overviewText->setAlignment(Qt::AlignCenter); + m_overviewImage->setVisible(false); + return; + } QFileInfo materialFileInfo(AZ::RPI::AssetUtils::GetProductPathByAssetId(m_editData.m_materialAsset.GetId()).c_str()); QFileInfo materialSourceFileInfo(m_editData.m_materialSourcePath.c_str()); QFileInfo materialTypeSourceFileInfo(m_editData.m_materialTypeSourcePath.c_str()); - QFileInfo materialParentSourceFileInfo(AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); + QFileInfo materialParentSourceFileInfo( + AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_editData.m_materialParentAsset.GetId()).c_str()); AZStd::string entityName; - AZ::ComponentApplicationBus::BroadcastResult( - entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); + AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_entityId); AZStd::string slotName; MaterialComponentRequestBus::EventResult( @@ -226,7 +226,8 @@ namespace AZ } if (!materialTypeSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); + materialInfo += + tr("Material Type %1").arg(materialTypeSourceFileInfo.fileName()); } if (!materialSourceFileInfo.fileName().isEmpty()) { @@ -234,14 +235,21 @@ namespace AZ } if (!materialParentSourceFileInfo.fileName().isEmpty()) { - materialInfo += tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); + materialInfo += + tr("Material Parent %1").arg(materialParentSourceFileInfo.fileName()); } materialInfo += tr(""); - materialInfoWidget->setText(materialInfo); - propertyGroupContainer->layout()->addWidget(materialInfoWidget); + m_overviewText->setText(materialInfo); + m_overviewText->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignTop); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupContainer); + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, + m_materialAssignmentId); + m_overviewImage->setPixmap(pixmap); + m_overviewImage->setVisible(true); + m_updatePreview |= pixmap.isNull(); } void MaterialPropertyInspector::AddUvNamesGroup() @@ -282,13 +290,8 @@ namespace AZ AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } - void MaterialPropertyInspector::Populate() + void MaterialPropertyInspector::AddPropertiesGroup() { - AddGroupsBegin(); - - AddDetailsGroup(); - AddUvNamesGroup(); - // Copy all of the properties from the material asset to the source data that will be exported for (const auto& groupDefinition : m_editData.m_materialTypeSourceData.GetGroupDefinitionsInDisplayOrder()) { @@ -327,10 +330,14 @@ namespace AZ [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); } + } + void MaterialPropertyInspector::Populate() + { + AddGroupsBegin(); + AddUvNamesGroup(); + AddPropertiesGroup(); AddGroupsEnd(); - - LoadOverridesFromEntity(); } void MaterialPropertyInspector::LoadOverridesFromEntity() @@ -375,6 +382,7 @@ namespace AZ m_dirtyPropertyFlags.set(); RunEditorMaterialFunctors(); RebuildAll(); + UpdateHeading(); } void MaterialPropertyInspector::SaveOverridesToEntity(bool commitChanges) @@ -398,6 +406,9 @@ namespace AZ MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); m_internalEditNotification = false; } + + // m_updatePreview should be set to true here for continuous preview updates as slider/color properties change but needs + // throttling } void MaterialPropertyInspector::RunEditorMaterialFunctors() @@ -607,7 +618,8 @@ namespace AZ MaterialComponentRequestBus::Event( m_entityId, &MaterialComponentRequestBus::Events::SetPropertyOverrides, m_materialAssignmentId, MaterialPropertyOverrideMap()); - QueueUpdateUI(); + m_updateUI = true; + m_updatePreview = true; }); action->setEnabled(IsLoaded()); @@ -702,10 +714,7 @@ namespace AZ void MaterialPropertyInspector::OnEntityActivated(const AZ::EntityId& entityId) { - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnEntityDeactivated(const AZ::EntityId& entityId) @@ -719,25 +728,39 @@ namespace AZ void MaterialPropertyInspector::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) { AZ_UNUSED(name); - if (m_entityId == entityId) - { - QueueUpdateUI(); - } + m_updateUI |= (m_entityId == entityId); } void MaterialPropertyInspector::OnTick(float deltaTime, ScriptTimePoint time) { AZ_UNUSED(time); AZ_UNUSED(deltaTime); - UpdateUI(); - AZ::TickBus::Handler::BusDisconnect(); + if (m_updateUI) + { + m_updateUI = false; + UpdateUI(); + } + + if (m_updatePreview) + { + m_updatePreview = false; + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_materialAssignmentId); + } } void MaterialPropertyInspector::OnMaterialsEdited() { - if (!m_internalEditNotification) + m_updateUI |= !m_internalEditNotification; + m_updatePreview = true; + } + + void MaterialPropertyInspector::OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap) + { + if (m_overviewImage && m_entityId == entityId && m_materialAssignmentId == materialAssignmentId) { - QueueUpdateUI(); + m_overviewImage->setPixmap(pixmap); } } @@ -761,16 +784,6 @@ namespace AZ LoadMaterial(m_entityId, m_materialAssignmentId); } } - - void MaterialPropertyInspector::QueueUpdateUI() - { - if (!AZ::TickBus::Handler::BusIsConnected()) - { - AZ::TickBus::Handler::BusConnect(); - } - } } // namespace EditorMaterialComponentInspector } // namespace Render } // namespace AZ - -//#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h index 048c1e19cb..82f46ebc90 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.h @@ -9,6 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include #include #include @@ -31,14 +32,13 @@ namespace AZ { namespace EditorMaterialComponentInspector { - using PropertyChangedCallback = AZStd::function; - class MaterialPropertyInspector : public AtomToolsFramework::InspectorWidget , public AzToolsFramework::IPropertyEditorNotify , public AZ::EntitySystemBus::Handler , public AZ::TickBus::Handler , public MaterialComponentNotificationBus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler { Q_OBJECT public: @@ -89,11 +89,19 @@ namespace AZ //! MaterialComponentNotificationBus::Handler overrides... void OnMaterialsEdited() override; - void UpdateUI(); - void QueueUpdateUI(); + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, + const AZ::Render::MaterialAssignmentId& materialAssignmentId, + const QPixmap& pixmap) override; + + void UpdateUI(); + + void CreateHeading(); + void UpdateHeading(); - void AddDetailsGroup(); void AddUvNamesGroup(); + void AddPropertiesGroup(); void LoadOverridesFromEntity(); void SaveOverridesToEntity(bool commitChanges); @@ -115,7 +123,10 @@ namespace AZ AZ::RPI::MaterialPropertyFlags m_dirtyPropertyFlags = {}; AZStd::unordered_map m_groups = {}; bool m_internalEditNotification = {}; - QLabel* m_messageLabel = {}; + bool m_updateUI = {}; + bool m_updatePreview = {}; + QLabel* m_overviewText = {}; + QLabel* m_overviewImage = {}; }; } // namespace EditorMaterialComponentInspector } // namespace Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index f5d38f48c4..d65fd0f2af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -6,23 +6,25 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include +#include +#include #include +#include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -100,6 +102,7 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &EditorMaterialComponentSlot::GetLabel) ->Attribute(AZ::Edit::Attributes::ShowProductAssetFileName, true) ->Attribute("ThumbnailCallback", &EditorMaterialComponentSlot::OpenPopupMenu) + ->Attribute("ThumbnailIcon", &EditorMaterialComponentSlot::GetPreviewPixmapData) ; } } @@ -118,6 +121,33 @@ namespace AZ } }; + AZStd::vector EditorMaterialComponentSlot::GetPreviewPixmapData() const + { + if (!GetActiveAssetId().IsValid()) + { + return {}; + } + + QPixmap pixmap; + EditorMaterialSystemComponentRequestBus::BroadcastResult( + pixmap, &EditorMaterialSystemComponentRequestBus::Events::GetRenderedMaterialPreview, m_entityId, m_id); + if (pixmap.isNull()) + { + if (m_updatePreview) + { + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; + } + return {}; + } + + QByteArray pixmapBytes; + QDataStream stream(&pixmapBytes, QIODevice::WriteOnly); + stream << pixmap; + return AZStd::vector(pixmapBytes.begin(), pixmapBytes.end()); + } + AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const { return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId(); @@ -169,14 +199,6 @@ namespace AZ ClearOverrides(); } - void EditorMaterialComponentSlot::ClearToDefaultAsset() - { - m_materialAsset = AZ::Data::Asset(GetDefaultAssetId(), AZ::AzTypeInfo::Uuid()); - MaterialComponentRequestBus::Event( - m_entityId, &MaterialComponentRequestBus::Events::SetMaterialOverride, m_id, m_materialAsset.GetId()); - ClearOverrides(); - } - void EditorMaterialComponentSlot::ClearOverrides() { MaterialComponentRequestBus::Event( @@ -315,6 +337,10 @@ namespace AZ AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast( &AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddDirtyEntity, m_entityId); + EditorMaterialSystemComponentRequestBus::Broadcast( + &EditorMaterialSystemComponentRequestBus::Events::RenderMaterialPreview, m_entityId, m_id); + m_updatePreview = false; + MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsEdited); AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h index 377fe9a18b..78fc7449de 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.h @@ -8,37 +8,52 @@ #pragma once -#include -#include - -#include -#include #include +#include +#include +#include +#include +#include namespace AZ { namespace Render { - static const size_t DefaultMaterialSlotIndex = std::numeric_limits::max(); - //! Details for a single editable material assignment struct EditorMaterialComponentSlot final { AZ_RTTI(EditorMaterialComponentSlot, "{344066EB-7C3D-4E92-B53D-3C9EBD546488}"); AZ_CLASS_ALLOCATOR(EditorMaterialComponentSlot, SystemAllocator, 0); - static void Reflect(ReflectContext* context); static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); + static void Reflect(ReflectContext* context); + //! Get cached preview image as a buffer to use as an RPE attribute + //! If a cached image isn't avalible then a request will be made to render one + AZStd::vector GetPreviewPixmapData() const; + + //! Returns the overridden asset id if it's valid, otherwise gets the default asseet id AZ::Data::AssetId GetActiveAssetId() const; + + //! Returns the default asseet id of the material provded by the model AZ::Data::AssetId GetDefaultAssetId() const; + + //! Returns the display name of the material slot AZStd::string GetLabel() const; + + //! Returns true if the active material asset has a source material bool HasSourceData() const; + //! Assign a new material override asset void SetAsset(const Data::AssetId& assetId); + + //! Assign a new material override asset void SetAsset(const Data::Asset& asset); + + //! Remove material and prperty overrides void Clear(); - void ClearToDefaultAsset(); + + //! Remove prperty overrides void ClearOverrides(); void OpenMaterialExporter(); @@ -54,6 +69,7 @@ namespace AZ void OpenPopupMenu(const AZ::Data::AssetId& assetId, const AZ::Data::AssetType& assetType); void OnMaterialChanged() const; void OnDataChanged() const; + mutable bool m_updatePreview = true; }; // Vector of slots for assignable or overridable material data. @@ -62,8 +78,8 @@ namespace AZ // Table containing all editable material data that is displayed in the edit context and inspector // The vector represents all the LODs that can have material overrides. // The container will be populated with every potential material slot on an associated model, using its default values. - // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment map - // as overrides that will be applied to material instances + // Whenever changes are made to this container, the modified values are copied into the controller configuration material assignment + // map as overrides that will be applied to material instances using EditorMaterialComponentSlotsByLodContainer = AZStd::vector; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp index a6b595940f..0939c8548b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.cpp @@ -6,7 +6,10 @@ * */ +#include #include +#include +#include #include #include #include @@ -16,11 +19,10 @@ #include #include #include -#include #include #include #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 @@ -30,6 +32,8 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") #include #include #include +#include +#include #include AZ_POP_DISABLE_WARNING @@ -72,11 +76,6 @@ namespace AZ incompatible.push_back(AZ_CRC("EditorMaterialSystem", 0x5c93bc4e)); } - void EditorMaterialSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC("ThumbnailerService", 0x65422b97)); - } - void EditorMaterialSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); @@ -89,25 +88,26 @@ namespace AZ void EditorMaterialSystemComponent::Activate() { + EditorMaterialSystemComponentNotificationBus::Handler::BusConnect(); EditorMaterialSystemComponentRequestBus::Handler::BusConnect(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); - - SetupThumbnails(); - m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); } void EditorMaterialSystemComponent::Deactivate() { - EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); + EditorMaterialSystemComponentRequestBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); - TeardownThumbnails(); + m_previewRenderer.reset(); m_materialBrowserInteractions.reset(); if (m_openMaterialEditorAction) @@ -154,11 +154,74 @@ namespace AZ } } - void EditorMaterialSystemComponent::OnApplicationAboutToStop() + void EditorMaterialSystemComponent::RenderMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) { - TeardownThumbnails(); + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + + if (m_previewRenderer) + { + AZ::Data::AssetId materialAssetId = {}; + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + MaterialComponentRequestBus::EventResult( + materialAssetId, entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, materialAssignmentId); + if (!materialAssetId.IsValid()) + { + return; + } + } + + AZ::Render::MaterialPropertyOverrideMap propertyOverrides; + AZ::Render::MaterialComponentRequestBus::EventResult( + propertyOverrides, entityId, &AZ::Render::MaterialComponentRequestBus::Events::GetPropertyOverrides, + materialAssignmentId); + + m_previewRenderer->AddCaptureRequest( + { 128, + AZStd::make_shared( + m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath), materialAssetId, + AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath), propertyOverrides), + []() + { + // failed + }, + [entityId, materialAssignmentId](const QPixmap& pixmap) + { + AZ::Render::EditorMaterialSystemComponentNotificationBus::Broadcast( + &AZ::Render::EditorMaterialSystemComponentNotificationBus::Events::OnRenderMaterialPreviewComplete, entityId, + materialAssignmentId, pixmap); + } }); + } } - + + QPixmap EditorMaterialSystemComponent::GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const + { + const auto& itr1 = m_materialPreviews.find(entityId); + if (itr1 != m_materialPreviews.end()) + { + const auto& itr2 = itr1->second.find(materialAssignmentId); + if (itr2 != itr1->second.end()) + { + return itr2->second; + } + } + return QPixmap(); + } + + void EditorMaterialSystemComponent::OnRenderMaterialPreviewComplete( + [[maybe_unused]] const AZ::EntityId& entityId, + [[maybe_unused]] const AZ::Render::MaterialAssignmentId& materialAssignmentId, + [[maybe_unused]] const QPixmap& pixmap) + { + m_materialPreviews[entityId][materialAssignmentId] = pixmap; + } + void EditorMaterialSystemComponent::OnPopulateToolMenuItems() { if (!m_openMaterialEditorAction) @@ -201,24 +264,19 @@ namespace AZ "Material Property Inspector", LyViewPane::CategoryTools, inspectorOptions); } - void EditorMaterialSystemComponent::SetupThumbnails() + void EditorMaterialSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::RegisterThumbnailProvider, MAKE_TCACHE(Thumbnails::MaterialThumbnailCache), - ThumbnailContext::DefaultContext); + AZ::TickBus::QueueFunction([this](){ + m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions); + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "EditorMaterialSystemComponent Preview Scene", "EditorMaterialSystemComponent Preview Pipeline")); + }); } - void EditorMaterialSystemComponent::TeardownThumbnails() + void EditorMaterialSystemComponent::OnApplicationAboutToStop() { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast( - &ThumbnailerRequests::UnregisterThumbnailProvider, Thumbnails::MaterialThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); + m_previewRenderer.reset(); + m_materialBrowserInteractions.reset(); } AzToolsFramework::AssetBrowser::SourceFileDetails EditorMaterialSystemComponent::GetSourceFileDetails( diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h index 7fa43ea309..e62c9b64dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialSystemComponent.h @@ -7,29 +7,31 @@ */ #pragma once +#include +#include +#include #include #include #include #include -#include #include - -#include - #include +#include namespace AZ { namespace Render { //! System component that manages launching and maintaining connections with the material editor. - class EditorMaterialSystemComponent + class EditorMaterialSystemComponent final : public AZ::Component - , private EditorMaterialSystemComponentRequestBus::Handler - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler - , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler - , private AzToolsFramework::EditorMenuNotificationBus::Handler - , private AzToolsFramework::EditorEvents::Bus::Handler + , public EditorMaterialSystemComponentNotificationBus::Handler + , public EditorMaterialSystemComponentRequestBus::Handler + , public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler + , public AzToolsFramework::EditorMenuNotificationBus::Handler + , public AzToolsFramework::EditorEvents::Bus::Handler + , public AzFramework::AssetCatalogEventBus::Handler + , public AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMaterialSystemComponent, "{96652157-DA0B-420F-B49C-0207C585144C}"); @@ -38,7 +40,6 @@ namespace AZ 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: @@ -51,9 +52,13 @@ namespace AZ //! EditorMaterialSystemComponentRequestBus::Handler overrides... void OpenMaterialEditor(const AZStd::string& sourcePath) override; void OpenMaterialInspector(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + void RenderMaterialPreview(const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) override; + QPixmap GetRenderedMaterialPreview( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId) const override; - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; + //! EditorMaterialSystemComponentNotificationBus::Handler overrides... + void OnRenderMaterialPreviewComplete( + const AZ::EntityId& entityId, const AZ::Render::MaterialAssignmentId& materialAssignmentId, const QPixmap& pixmap)override; //! AssetBrowserInteractionNotificationBus::Handler overrides... AzToolsFramework::AssetBrowser::SourceFileDetails GetSourceFileDetails(const char* fullSourceFileName) override; @@ -65,12 +70,17 @@ namespace AZ // AztoolsFramework::EditorEvents::Bus::Handler overrides... void NotifyRegisterViews() override; - void SetupThumbnails(); - void TeardownThumbnails(); + + // AzFramework::AssetCatalogEventBus::Handler overrides ... + void OnCatalogLoaded(const char* catalogFile) override; + + // AzFramework::ApplicationLifecycleEvents overrides... + void OnApplicationAboutToStop() override; QAction* m_openMaterialEditorAction = nullptr; - AZStd::unique_ptr m_materialBrowserInteractions; + AZStd::unique_ptr m_previewRenderer; + AZStd::unordered_map> m_materialPreviews; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp deleted file mode 100644 index 2931b647e5..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int MaterialThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnail - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnail::MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::MaterialAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("MaterialThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void MaterialThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::MaterialAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, - MaterialThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - MaterialThumbnail::~MaterialThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void MaterialThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void MaterialThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void MaterialThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && - m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // MaterialThumbnailCache - ////////////////////////////////////////////////////////////////////////// - MaterialThumbnailCache::MaterialThumbnailCache() - : ThumbnailCache() - { - } - - MaterialThumbnailCache::~MaterialThumbnailCache() = default; - - int MaterialThumbnailCache::GetPriority() const - { - // Material thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* MaterialThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool MaterialThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return - GetAssetId(key, RPI::MaterialAsset::RTTI_Type()).IsValid() && - // in case it's a source scene file, it will contain both material and model products - // model thumbnails are handled by MeshThumbnail - !GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h deleted file mode 100644 index 8f2053ba67..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialThumbnail.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ - class MaterialThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - MaterialThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MaterialThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - /** - * Cache configuration for large material thumbnails - */ - class MaterialThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - MaterialThumbnailCache(); - ~MaterialThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "Material Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp index 8b2f6c8a11..c6a7ff1f50 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.cpp @@ -6,13 +6,10 @@ * */ -#include #include #include -#include -#include -#include -#include +#include +#include namespace AZ { @@ -47,11 +44,6 @@ namespace AZ incompatible.push_back(AZ_CRC_CE("EditorMeshSystem")); } - void EditorMeshSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC_CE("ThumbnailerService")); - } - void EditorMeshSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { AZ_UNUSED(dependent); @@ -59,39 +51,10 @@ namespace AZ void EditorMeshSystemComponent::Activate() { - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); - SetupThumbnails(); } void EditorMeshSystemComponent::Deactivate() { - TeardownThumbnails(); - AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); - } - - void EditorMeshSystemComponent::OnApplicationAboutToStop() - { - TeardownThumbnails(); - } - - void EditorMeshSystemComponent::SetupThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::RegisterThumbnailProvider, - MAKE_TCACHE(Thumbnails::MeshThumbnailCache), - ThumbnailContext::DefaultContext); - } - - void EditorMeshSystemComponent::TeardownThumbnails() - { - using namespace AzToolsFramework::Thumbnailer; - using namespace LyIntegration; - - ThumbnailerRequestsBus::Broadcast(&ThumbnailerRequests::UnregisterThumbnailProvider, - Thumbnails::MeshThumbnailCache::ProviderName, - ThumbnailContext::DefaultContext); } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h index 64d72bc33d..a784785830 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshSystemComponent.h @@ -8,7 +8,6 @@ #pragma once #include -#include namespace AZ { @@ -17,7 +16,6 @@ namespace AZ //! System component that sets up necessary logic related to EditorMeshComponent. class EditorMeshSystemComponent : public AZ::Component - , private AzFramework::ApplicationLifecycleEvents::Bus::Handler { public: AZ_COMPONENT(EditorMeshSystemComponent, "{4D332E3D-C4FC-410B-A915-8E234CBDD4EC}"); @@ -26,20 +24,12 @@ namespace AZ 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 overrides... void Activate() override; void Deactivate() override; - - private: - // AzFramework::ApplicationLifecycleEvents overrides... - void OnApplicationAboutToStop() override; - - void SetupThumbnails(); - void TeardownThumbnails(); }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp deleted file mode 100644 index 845197d939..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - static constexpr const int MeshThumbnailSize = 512; // 512 is the default size in render to texture pass - - ////////////////////////////////////////////////////////////////////////// - // MeshThumbnail - ////////////////////////////////////////////////////////////////////////// - MeshThumbnail::MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) - : Thumbnail(key) - { - m_assetId = GetAssetId(key, RPI::ModelAsset::RTTI_Type()); - if (!m_assetId.IsValid()) - { - AZ_Error("MeshThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); - m_state = State::Failed; - return; - } - - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); - } - - void MeshThumbnail::LoadThread() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( - RPI::ModelAsset::RTTI_Type(), - &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, - m_key, - MeshThumbnailSize); - // wait for response from thumbnail renderer - m_renderWait.acquire(); - } - - MeshThumbnail::~MeshThumbnail() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); - } - - void MeshThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) - { - m_pixmap = thumbnailImage; - m_renderWait.release(); - } - - void MeshThumbnail::ThumbnailFailedToRender() - { - m_state = State::Failed; - m_renderWait.release(); - } - - void MeshThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) - { - if (m_assetId == assetId && - m_state == State::Ready) - { - m_state = State::Unloaded; - Load(); - } - } - - ////////////////////////////////////////////////////////////////////////// - // MeshThumbnailCache - ////////////////////////////////////////////////////////////////////////// - MeshThumbnailCache::MeshThumbnailCache() - : ThumbnailCache() - { - } - - MeshThumbnailCache::~MeshThumbnailCache() = default; - - int MeshThumbnailCache::GetPriority() const - { - // Material thumbnails override default source thumbnails, so carry higher priority - return 1; - } - - const char* MeshThumbnailCache::GetProviderName() const - { - return ProviderName; - } - - bool MeshThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const - { - return GetAssetId(key, RPI::ModelAsset::RTTI_Type()).IsValid(); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - -#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h deleted file mode 100644 index 872e1029d2..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshThumbnail.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - /** - * Custom material or model thumbnail that detects when an asset changes and updates the thumbnail - */ - class MeshThumbnail - : public AzToolsFramework::Thumbnailer::Thumbnail - , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler - , private AzFramework::AssetCatalogEventBus::Handler - { - Q_OBJECT - public: - MeshThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); - ~MeshThumbnail() override; - - //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... - void ThumbnailRendered(const QPixmap& thumbnailImage) override; - void ThumbnailFailedToRender() override; - - protected: - void LoadThread() override; - - private: - // AzFramework::AssetCatalogEventBus::Handler interface overrides... - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; - - AZStd::binary_semaphore m_renderWait; - Data::AssetId m_assetId; - }; - - /** - * Cache configuration for large material thumbnails - */ - class MeshThumbnailCache - : public AzToolsFramework::Thumbnailer::ThumbnailCache - { - public: - MeshThumbnailCache(); - ~MeshThumbnailCache() override; - - int GetPriority() const override; - const char* GetProviderName() const override; - - static constexpr const char* ProviderName = "Mesh Thumbnails"; - - protected: - bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp new file mode 100644 index 0000000000..91b6d2b02a --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + SharedPreviewContent::SharedPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides) + : m_scene(scene) + , m_view(view) + , m_entityContextId(entityContextId) + , m_materialPropertyOverrides(materialPropertyOverrides) + { + // Create preview model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, m_entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "SharedPreviewContentModel"); + m_modelEntity->CreateComponent(Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Init(); + m_modelEntity->Activate(); + + m_modelAsset.Create(modelAssetId); + m_materialAsset.Create(materialAssetId); + m_lightingPresetAsset.Create(lightingPresetAssetId); + } + + SharedPreviewContent::~SharedPreviewContent() + { + if (m_modelEntity) + { + m_modelEntity->Deactivate(); + AzFramework::EntityContextRequestBus::Event( + m_entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + } + } + + void SharedPreviewContent::Load() + { + m_modelAsset.QueueLoad(); + m_materialAsset.QueueLoad(); + m_lightingPresetAsset.QueueLoad(); + } + + bool SharedPreviewContent::IsReady() const + { + return (!m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady()) && + (!m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady()) && + (!m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady()); + } + + bool SharedPreviewContent::IsError() const + { + return m_modelAsset.IsError() || m_materialAsset.IsError() || m_lightingPresetAsset.IsError(); + } + + void SharedPreviewContent::ReportErrors() + { + AZ_Warning( + "SharedPreviewContent", !m_modelAsset.GetId().IsValid() || m_modelAsset.IsReady(), "Asset failed to load in time: %s", + m_modelAsset.ToString().c_str()); + AZ_Warning( + "SharedPreviewContent", !m_materialAsset.GetId().IsValid() || m_materialAsset.IsReady(), "Asset failed to load in time: %s", + m_materialAsset.ToString().c_str()); + AZ_Warning( + "SharedPreviewContent", !m_lightingPresetAsset.GetId().IsValid() || m_lightingPresetAsset.IsReady(), + "Asset failed to load in time: %s", m_lightingPresetAsset.ToString().c_str()); + } + + void SharedPreviewContent::Update() + { + UpdateModel(); + UpdateLighting(); + UpdateCamera(); + } + + void SharedPreviewContent::UpdateModel() + { + Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MeshComponentRequestBus::Events::SetModelAsset, m_modelAsset); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetMaterialOverride, + Render::DefaultMaterialAssignmentId, m_materialAsset.GetId()); + + Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &Render::MaterialComponentRequestBus::Events::SetPropertyOverrides, + Render::DefaultMaterialAssignmentId, m_materialPropertyOverrides); + } + + void SharedPreviewContent::UpdateLighting() + { + if (m_lightingPresetAsset.IsReady()) + { + auto preset = m_lightingPresetAsset->GetDataAs(); + if (preset) + { + auto iblFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); + auto postProcessSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId()); + auto exposureControlSettingInterface = postProcessSettingInterface->GetOrCreateExposureControlSettingsInterface(); + auto directionalLightFeatureProcessor = + m_scene->GetFeatureProcessor(); + auto skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + skyboxFeatureProcessor->Enable(true); + skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); + + Camera::Configuration cameraConfig; + cameraConfig.m_fovRadians = FieldOfView; + cameraConfig.m_nearClipDistance = NearDist; + cameraConfig.m_farClipDistance = FarDist; + cameraConfig.m_frustumWidth = 100.0f; + cameraConfig.m_frustumHeight = 100.0f; + + AZStd::vector lightHandles; + + preset->ApplyLightingPreset( + iblFeatureProcessor, skyboxFeatureProcessor, exposureControlSettingInterface, directionalLightFeatureProcessor, + cameraConfig, lightHandles); + } + } + } + + void SharedPreviewContent::UpdateCamera() + { + // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it + Vector3 center = {}; + float radius = {}; + if (m_modelAsset.IsReady()) + { + m_modelAsset->GetAabb().GetAsSphere(center, radius); + } + + const auto distance = radius + NearDist; + const auto cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), CameraRotationAngle); + const auto cameraPosition = center + cameraRotation.TransformVector(Vector3(0.0f, distance, 0.0f)); + const auto cameraTransform = Transform::CreateLookAt(cameraPosition, center); + m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h new file mode 100644 index 0000000000..7308aa19bc --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewContent.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + //! Creates a simple scene used for most previews and thumbnails + class SharedPreviewContent final : public AtomToolsFramework::PreviewContent + { + public: + AZ_CLASS_ALLOCATOR(SharedPreviewContent, AZ::SystemAllocator, 0); + + SharedPreviewContent( + RPI::ScenePtr scene, + RPI::ViewPtr view, + AZ::Uuid entityContextId, + const Data::AssetId& modelAssetId, + const Data::AssetId& materialAssetId, + const Data::AssetId& lightingPresetAssetId, + const Render::MaterialPropertyOverrideMap& materialPropertyOverrides); + + ~SharedPreviewContent() override; + + void Load() override; + bool IsReady() const override; + bool IsError() const override; + void ReportErrors() override; + void Update() override; + + private: + void UpdateModel(); + void UpdateLighting(); + void UpdateCamera(); + + static constexpr float AspectRatio = 1.0f; + static constexpr float NearDist = 0.001f; + static constexpr float FarDist = 100.0f; + static constexpr float FieldOfView = Constants::HalfPi; + static constexpr float CameraRotationAngle = Constants::QuarterPi / 2.0f; + + RPI::ScenePtr m_scene; + RPI::ViewPtr m_view; + AZ::Uuid m_entityContextId; + Entity* m_modelEntity = nullptr; + + Data::Asset m_modelAsset; + Data::Asset m_materialAsset; + Data::Asset m_lightingPresetAsset; + Render::MaterialPropertyOverrideMap m_materialPropertyOverrides; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp similarity index 55% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp index c8f67138ef..c2988cf53d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.cpp @@ -11,37 +11,42 @@ #include #include #include -#include +#include +#include namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType) + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId) { - static const Data::AssetId invalidAssetId; - // if it's a source thumbnail key, find first product with a matching asset type auto sourceKey = azrtti_cast(key.data()); if (sourceKey) { bool foundIt = false; AZStd::vector productsAssetInfo; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, sourceKey->GetSourceUuid(), productsAssetInfo); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + foundIt, &AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID, + sourceKey->GetSourceUuid(), productsAssetInfo); if (!foundIt) { - return invalidAssetId; + return defaultAssetId; } - auto assetInfoIt = AZStd::find_if(productsAssetInfo.begin(), productsAssetInfo.end(), + auto assetInfoIt = AZStd::find_if( + productsAssetInfo.begin(), productsAssetInfo.end(), [&assetType](const Data::AssetInfo& assetInfo) { return assetInfo.m_assetType == assetType; }); if (assetInfoIt == productsAssetInfo.end()) { - return invalidAssetId; + return defaultAssetId; } return assetInfoIt->m_assetId; @@ -53,10 +58,9 @@ namespace AZ { return productKey->GetAssetId(); } - return invalidAssetId; + return defaultAssetId; } - QString WordWrap(const QString& string, int maxLength) { QString result; @@ -81,6 +85,32 @@ namespace AZ } return result; } - } // namespace Thumbnails + + AZStd::unordered_set GetSupportedAssetTypes() + { + return { RPI::AnyAsset::RTTI_Type(), RPI::MaterialAsset::RTTI_Type(), RPI::ModelAsset::RTTI_Type() }; + } + + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + { + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); + if (assetId.IsValid()) + { + if (typeId == RPI::AnyAsset::RTTI_Type()) + { + AZ::Data::AssetInfo assetInfo; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, assetId); + return AzFramework::StringFunc::EndsWith(assetInfo.m_relativePath.c_str(), "lightingpreset.azasset"); + } + return true; + } + } + + return false; + } + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h similarity index 53% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h index e4efcd6b49..6c5d83d22a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/ThumbnailUtils.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewUtils.h @@ -18,13 +18,23 @@ namespace AZ { namespace LyIntegration { - namespace Thumbnails + namespace SharedPreviewUtils { //! Get assetId by assetType that belongs to either source or product thumbnail key - Data::AssetId GetAssetId(AzToolsFramework::Thumbnailer::SharedThumbnailKey key, const Data::AssetType& assetType); + Data::AssetId GetAssetId( + AzToolsFramework::Thumbnailer::SharedThumbnailKey key, + const Data::AssetType& assetType, + const Data::AssetId& defaultAssetId = {}); - //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word wrap needed + //! Word wrap function for previewer QLabel, since by default it does not break long words such as filenames, so manual word + //! wrap needed QString WordWrap(const QString& string, int maxLength); - } // namespace Thumbnails + + //! Get the set of all asset types supported by the shared preview + AZStd::unordered_set GetSupportedAssetTypes(); + + //! Determine if a thumbnail key has an asset supported by the shared preview + bool IsSupportedAssetType(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + } // namespace SharedPreviewUtils } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp similarity index 69% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp index 9730c7d4a9..942af55721 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.cpp @@ -7,23 +7,21 @@ */ #include - +#include #include #include -#include -#include #include - -#include -#include +#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 +// 4251: class needs to have dll-interface to be used by clients of class // 4800: forcing value to bool 'true' or 'false' (performance warning) AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include -#include #include +#include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -32,18 +30,22 @@ namespace AZ { static constexpr int CharWidth = 6; - CommonPreviewer::CommonPreviewer(QWidget* parent) + SharedPreviewer::SharedPreviewer(QWidget* parent) : Previewer(parent) - , m_ui(new Ui::CommonPreviewerClass()) + , m_ui(new Ui::SharedPreviewerClass()) { m_ui->setupUi(this); } - CommonPreviewer::~CommonPreviewer() + SharedPreviewer::~SharedPreviewer() { } - void CommonPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) + void SharedPreviewer::Clear() const + { + } + + void SharedPreviewer::Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) { using namespace AzToolsFramework::AssetBrowser; using namespace AzToolsFramework::Thumbnailer; @@ -54,23 +56,23 @@ namespace AZ UpdateFileInfo(); } - const QString& CommonPreviewer::GetName() const + const QString& SharedPreviewer::GetName() const { return m_name; } - void CommonPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) + void SharedPreviewer::resizeEvent([[maybe_unused]] QResizeEvent* event) { m_ui->m_previewWidget->setMaximumHeight(m_ui->m_previewWidget->width()); UpdateFileInfo(); } - void CommonPreviewer::UpdateFileInfo() const + void SharedPreviewer::UpdateFileInfo() const { - m_ui->m_fileInfoLabel->setText(Thumbnails::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); + m_ui->m_fileInfoLabel->setText(SharedPreviewUtils::WordWrap(m_fileInfo, m_ui->m_fileInfoLabel->width() / CharWidth)); } } // namespace LyIntegration } // namespace AZ -#include +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h similarity index 73% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h index 1dfa8788e0..ab6f793982 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.h @@ -5,22 +5,23 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #if !defined(Q_MOC_RUN) -#include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include +#include AZ_POP_DISABLE_WARNING #endif namespace Ui { - class CommonPreviewerClass; + class SharedPreviewerClass; } namespace AzToolsFramework @@ -30,8 +31,8 @@ namespace AzToolsFramework class ProductAssetBrowserEntry; class SourceAssetBrowserEntry; class AssetBrowserEntry; - } -} + } // namespace AssetBrowser +} // namespace AzToolsFramework class QResizeEvent; @@ -39,18 +40,17 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewer final - : public AzToolsFramework::AssetBrowser::Previewer + class SharedPreviewer final : public AzToolsFramework::AssetBrowser::Previewer { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(CommonPreviewer, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewer, AZ::SystemAllocator, 0); - explicit CommonPreviewer(QWidget* parent = nullptr); - ~CommonPreviewer(); + explicit SharedPreviewer(QWidget* parent = nullptr); + ~SharedPreviewer(); // AzToolsFramework::AssetBrowser::Previewer overrides... - void Clear() const override {} + void Clear() const override; void Display(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) override; const QString& GetName() const override; @@ -60,9 +60,9 @@ namespace AZ private: void UpdateFileInfo() const; - QScopedPointer m_ui; + QScopedPointer m_ui; QString m_fileInfo; - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui similarity index 97% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui index f97dde0a1f..139231d607 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewer.ui +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewer.ui @@ -1,7 +1,7 @@ - CommonPreviewerClass - + SharedPreviewerClass + 0 diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp new file mode 100644 index 0000000000..14d6e5b5f0 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + AzToolsFramework::AssetBrowser::Previewer* SharedPreviewerFactory::CreatePreviewer(QWidget* parent) const + { + return new SharedPreviewer(parent); + } + + bool SharedPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const + { + return SharedPreviewUtils::IsSupportedAssetType(entry->GetThumbnailKey()); + } + + const QString& SharedPreviewerFactory::GetName() const + { + return m_name; + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h similarity index 76% rename from Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h rename to Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h index 1f9cc9d5df..e3021cb8ab 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedPreviewerFactory.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -18,14 +19,13 @@ namespace AZ { namespace LyIntegration { - class CommonPreviewerFactory final - : public AzToolsFramework::AssetBrowser::PreviewerFactory + class SharedPreviewerFactory final : public AzToolsFramework::AssetBrowser::PreviewerFactory { public: - AZ_CLASS_ALLOCATOR(CommonPreviewerFactory, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(SharedPreviewerFactory, AZ::SystemAllocator, 0); - CommonPreviewerFactory() = default; - ~CommonPreviewerFactory() = default; + SharedPreviewerFactory() = default; + ~SharedPreviewerFactory() = default; // AzToolsFramework::AssetBrowser::PreviewerFactory overrides... AzToolsFramework::AssetBrowser::Previewer* CreatePreviewer(QWidget* parent = nullptr) const override; @@ -33,7 +33,7 @@ namespace AZ const QString& GetName() const override; private: - QString m_name = "CommonPreviewer"; + QString m_name = "SharedPreviewer"; }; } // namespace LyIntegration } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp new file mode 100644 index 0000000000..ebfad39229 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + static constexpr const int SharedThumbnailSize = 256; + + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnail + ////////////////////////////////////////////////////////////////////////// + SharedThumbnail::SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) + : Thumbnail(key) + { + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + const AZ::Data::AssetId& assetId = SharedPreviewUtils::GetAssetId(key, typeId); + if (assetId.IsValid()) + { + m_assetId = assetId; + m_typeId = typeId; + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusConnect(key); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); + return; + } + } + + AZ_Error("SharedThumbnail", false, "Failed to find matching assetId for the thumbnailKey."); + m_state = State::Failed; + } + + void SharedThumbnail::LoadThread() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + m_typeId, &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, SharedThumbnailSize); + // wait for response from thumbnail renderer + m_renderWait.acquire(); + } + + SharedThumbnail::~SharedThumbnail() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler::BusDisconnect(); + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); + } + + void SharedThumbnail::ThumbnailRendered(const QPixmap& thumbnailImage) + { + m_pixmap = thumbnailImage; + m_renderWait.release(); + } + + void SharedThumbnail::ThumbnailFailedToRender() + { + m_state = State::Failed; + m_renderWait.release(); + } + + void SharedThumbnail::OnCatalogAssetChanged([[maybe_unused]] const AZ::Data::AssetId& assetId) + { + if (m_assetId == assetId && m_state == State::Ready) + { + m_state = State::Unloaded; + Load(); + } + } + + ////////////////////////////////////////////////////////////////////////// + // SharedThumbnailCache + ////////////////////////////////////////////////////////////////////////// + SharedThumbnailCache::SharedThumbnailCache() + : ThumbnailCache() + { + } + + SharedThumbnailCache::~SharedThumbnailCache() = default; + + int SharedThumbnailCache::GetPriority() const + { + // Thumbnails override default source thumbnails, so carry higher priority + return 1; + } + + const char* SharedThumbnailCache::GetProviderName() const + { + return ProviderName; + } + + bool SharedThumbnailCache::IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const + { + return SharedPreviewUtils::IsSupportedAssetType(key); + } + } // namespace LyIntegration +} // namespace AZ + +#include diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h new file mode 100644 index 0000000000..d65e94a7a3 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnail.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +namespace AZ +{ + namespace LyIntegration + { + //! Custom thumbnail that detects when an asset changes and updates the thumbnail + class SharedThumbnail final + : public AzToolsFramework::Thumbnailer::Thumbnail + , public AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Handler + , private AzFramework::AssetCatalogEventBus::Handler + { + Q_OBJECT + public: + SharedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key); + ~SharedThumbnail() override; + + //! AzToolsFramework::ThumbnailerRendererNotificationBus::Handler overrides... + void ThumbnailRendered(const QPixmap& thumbnailImage) override; + void ThumbnailFailedToRender() override; + + protected: + void LoadThread() override; + + private: + // AzFramework::AssetCatalogEventBus::Handler interface overrides... + void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; + + AZStd::binary_semaphore m_renderWait; + Data::AssetId m_assetId; + AZ::Uuid m_typeId; + }; + + //! Cache configuration for large thumbnails + class SharedThumbnailCache final : public AzToolsFramework::Thumbnailer::ThumbnailCache + { + public: + SharedThumbnailCache(); + ~SharedThumbnailCache() override; + + int GetPriority() const override; + const char* GetProviderName() const override; + + static constexpr const char* ProviderName = "Common Feature Shared Thumbnail= Provider"; + + protected: + bool IsSupportedThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey key) const override; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp new file mode 100644 index 0000000000..c20cef548f --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + SharedThumbnailRenderer::SharedThumbnailRenderer() + { + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "SharedThumbnailRenderer Preview Scene", "SharedThumbnailRenderer Preview Pipeline")); + + m_defaultModelAsset.Create(DefaultModelAssetId, true); + m_defaultMaterialAsset.Create(DefaultMaterialAssetId, true); + m_defaultLightingPresetAsset.Create(DefaultLightingPresetAssetId, true); + + for (const AZ::Uuid& typeId : SharedPreviewUtils::GetSupportedAssetTypes()) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(typeId); + } + SystemTickBus::Handler::BusConnect(); + } + + SharedThumbnailRenderer::~SharedThumbnailRenderer() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); + } + + void SharedThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) + { + m_previewRenderer->AddCaptureRequest( + { thumbnailSize, + AZStd::make_shared( + m_previewRenderer->GetScene(), m_previewRenderer->GetView(), m_previewRenderer->GetEntityContextId(), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::ModelAsset::RTTI_Type(), DefaultModelAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::MaterialAsset::RTTI_Type(), DefaultMaterialAssetId), + SharedPreviewUtils::GetAssetId(thumbnailKey, RPI::AnyAsset::RTTI_Type(), DefaultLightingPresetAssetId), + Render::MaterialPropertyOverrideMap()), + [thumbnailKey]() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); + }, + [thumbnailKey](const QPixmap& pixmap) + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( + thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, pixmap); + } }); + } + + bool SharedThumbnailRenderer::Installed() const + { + return true; + } + + void SharedThumbnailRenderer::OnSystemTick() + { + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); + } + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h new file mode 100644 index 0000000000..bcefbd6f4e --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SharedPreview/SharedThumbnailRenderer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + namespace LyIntegration + { + //! Provides custom rendering thumbnails of supported asset types + class SharedThumbnailRenderer final + : public AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler + , public SystemTickBus::Handler + { + public: + AZ_CLASS_ALLOCATOR(SharedThumbnailRenderer, AZ::SystemAllocator, 0); + + SharedThumbnailRenderer(); + ~SharedThumbnailRenderer(); + + private: + //! ThumbnailerRendererRequestsBus::Handler interface overrides... + void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; + bool Installed() const override; + + //! SystemTickBus::Handler interface overrides... + void OnSystemTick() override; + + // Default assets to be kept loaded and used for rendering if not overridden + static constexpr const char* DefaultLightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; + const Data::AssetId DefaultLightingPresetAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultLightingPresetPath); + Data::Asset m_defaultLightingPresetAsset; + + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; + const Data::AssetId DefaultModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultModelPath); + Data::Asset m_defaultModelAsset; + + static constexpr const char* DefaultMaterialPath = ""; + const Data::AssetId DefaultMaterialAssetId; + Data::Asset m_defaultMaterialAsset; + + AZStd::unique_ptr m_previewRenderer; + }; + } // namespace LyIntegration +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp deleted file mode 100644 index 856d38d6cb..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Preview/CommonPreviewerFactory.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - AzToolsFramework::AssetBrowser::Previewer* CommonPreviewerFactory::CreatePreviewer(QWidget* parent) const - { - return new CommonPreviewer(parent); - } - - bool CommonPreviewerFactory::IsEntrySupported(const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry) const - { - return - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::MaterialAsset::RTTI_Type()).IsValid() || - Thumbnails::GetAssetId(entry->GetThumbnailKey(), RPI::ModelAsset::RTTI_Type()).IsValid(); - } - - const QString& CommonPreviewerFactory::GetName() const - { - return m_name; - } - } // 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 deleted file mode 100644 index 9c69fdd995..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - CommonThumbnailRenderer::CommonThumbnailRenderer() - : m_data(new ThumbnailRendererData) - { - // CommonThumbnailRenderer supports both models and materials, but we connect on materialAssetType - // since MaterialOrModelThumbnail dispatches event on materialAssetType address too - 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() - { - if (m_currentStep != Step::None) - { - CommonThumbnailRenderer::SetStep(Step::ReleaseResources); - } - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect(); - SystemTickBus::Handler::BusDisconnect(); - ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect(); - } - - void CommonThumbnailRenderer::SetStep(Step step) - { - if (m_currentStep != Step::None) - { - m_steps[m_currentStep]->Stop(); - } - m_currentStep = step; - m_steps[m_currentStep]->Start(); - } - - Step CommonThumbnailRenderer::GetStep() const - { - return m_currentStep; - } - - bool CommonThumbnailRenderer::Installed() const - { - return true; - } - - void CommonThumbnailRenderer::OnSystemTick() - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents(); - } - - const AZStd::vector& CommonThumbnailRenderer::GetCustomFeatureProcessors() const - { - return m_minimalFeatureProcessors; - } - - AZStd::shared_ptr CommonThumbnailRenderer::GetData() const - { - return m_data; - } - - void CommonThumbnailRenderer::RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) - { - m_data->m_thumbnailSize = thumbnailSize; - m_data->m_thumbnailQueue.push(thumbnailKey); - if (m_currentStep == Step::None) - { - SetStep(Step::Initialize); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h deleted file mode 100644 index 7c3b17e104..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/CommonThumbnailRenderer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#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) -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ThumbnailRendererStep; - - //! Provides custom rendering of material and model thumbnails - class CommonThumbnailRenderer - : public ThumbnailRendererContext - , private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler - , private SystemTickBus::Handler - , private ThumbnailFeatureProcessorProviderBus::Handler - { - public: - AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0) - - CommonThumbnailRenderer(); - ~CommonThumbnailRenderer(); - - //! ThumbnailRendererContext overrides... - void SetStep(Step step) override; - Step GetStep() const override; - AZStd::shared_ptr GetData() const override; - - private: - //! ThumbnailerRendererRequestsBus::Handler interface overrides... - void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override; - bool Installed() const override; - - //! 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 -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h deleted file mode 100644 index d3bb2be64a..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererContext.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - struct ThumbnailRendererData; - - enum class Step - { - None, - Initialize, - FindThumbnailToRender, - WaitForAssetsToLoad, - Capture, - ReleaseResources - }; - - //! An interface for ThumbnailRendererSteps to communicate with thumbnail renderer - class ThumbnailRendererContext - { - public: - virtual void SetStep(Step step) = 0; - virtual Step GetStep() const = 0; - virtual AZStd::shared_ptr GetData() const = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h deleted file mode 100644 index c471cf90d7..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "Atom/RPI.Reflect/Model/ModelAsset.h" - -#include -#include -#include -#include -#include -#include - -namespace AzFramework -{ - class Scene; -} - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! ThumbnailRendererData encapsulates all data used by thumbnail renderer and caches assets - struct ThumbnailRendererData final - { - static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; - static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; - - RPI::ScenePtr m_scene; - AZStd::string m_sceneName = "Material Thumbnail Scene"; - AZStd::string m_pipelineName = "Material Thumbnail Pipeline"; - AZStd::shared_ptr m_frameworkScene; - RPI::RenderPipelinePtr m_renderPipeline; - AZStd::unique_ptr m_entityContext; - AZStd::vector m_passHierarchy; - - RPI::ViewPtr m_view = nullptr; - Entity* m_modelEntity = nullptr; - - int m_thumbnailSize = 512; - - //! Incoming thumbnail requests are appended to this queue and processed one at a time in OnTick function. - AZStd::queue m_thumbnailQueue; - //! Current thumbnail key being rendered. - AzToolsFramework::Thumbnailer::SharedThumbnailKey m_thumbnailKeyRendered; - - Data::Asset m_lightingPresetAsset; - - Data::Asset m_defaultModelAsset; - //! Model asset about to be rendered - Data::Asset m_modelAsset; - - Data::Asset m_defaultMaterialAsset; - //! Material asset about to be rendered - Data::Asset m_materialAsset; - - AZStd::unordered_set m_assetsToLoad; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp deleted file mode 100644 index f728d56bbc..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - CaptureStep::CaptureStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void CaptureStep::Start() - { - if (!m_context->GetData()->m_materialAsset || - !m_context->GetData()->m_modelAsset) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - return; - } - Render::MaterialComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MaterialComponentRequestBus::Events::SetDefaultMaterialOverride, - m_context->GetData()->m_materialAsset.GetId()); - Render::MeshComponentRequestBus::Event( - m_context->GetData()->m_modelEntity->GetId(), - &Render::MeshComponentRequestBus::Events::SetModelAsset, - m_context->GetData()->m_modelAsset); - RepositionCamera(); - m_readyToCapture = true; - m_ticksToCapture = 1; - TickBus::Handler::BusConnect(); - } - - void CaptureStep::Stop() - { - m_context->GetData()->m_renderPipeline->RemoveFromRenderTick(); - TickBus::Handler::BusDisconnect(); - Render::FrameCaptureNotificationBus::Handler::BusDisconnect(); - } - - void CaptureStep::RepositionCamera() const - { - // Get bounding sphere of the model asset and estimate how far the camera needs to be see all of it - const Aabb& aabb = m_context->GetData()->m_modelAsset->GetAabb(); - Vector3 modelCenter; - float radius; - aabb.GetAsSphere(modelCenter, radius); - - float distance = StartingDistanceMultiplier * - GetMax(GetMax(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + - DepthNear; - const Quaternion cameraRotation = Quaternion::CreateFromAxisAngle(Vector3::CreateAxisZ(), StartingRotationAngle); - Vector3 cameraPosition(modelCenter.GetX(), modelCenter.GetY() - distance, modelCenter.GetZ()); - cameraPosition = cameraRotation.TransformVector(cameraPosition); - auto cameraTransform = Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); - m_context->GetData()->m_view->SetCameraTransform(Matrix3x4::CreateFromTransform(cameraTransform)); - } - - void CaptureStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { - if (m_readyToCapture && m_ticksToCapture-- <= 0) - { - m_context->GetData()->m_renderPipeline->AddToRenderTickOnce(); - - RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result) - { - if (!result.m_dataBuffer) - { - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - return; - } - uchar* data = result.m_dataBuffer.get()->data(); - QImage image( - data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888); - QPixmap pixmap; - pixmap.convertFromImage(image); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered, - pixmap); - }; - - Render::FrameCaptureNotificationBus::Handler::BusConnect(); - bool startedCapture = false; - Render::FrameCaptureRequestBus::BroadcastResult( - startedCapture, - &Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, - m_context->GetData()->m_passHierarchy, AZStd::string("Output"), readbackCallback, RPI::PassAttachmentReadbackOption::Output); - // Reset the capture flag if the capture request was successful. Otherwise try capture it again next tick. - if (startedCapture) - { - m_readyToCapture = false; - } - } - } - - void CaptureStep::OnCaptureFinished([[maybe_unused]] Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info) - { - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h deleted file mode 100644 index e93828e3b8..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! CaptureStep renders a thumbnail to a pixmap and notifies MaterialOrModelThumbnail once finished - class CaptureStep - : public ThumbnailRendererStep - , private TickBus::Handler - , private Render::FrameCaptureNotificationBus::Handler - { - public: - CaptureStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - //! Places the camera so that the entire model is visible - void RepositionCamera() const; - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - //! Render::FrameCaptureNotificationBus::Handler overrides... - void OnCaptureFinished(Render::FrameCaptureResult result, const AZStd::string& info) override; - - static constexpr float DepthNear = 0.01f; - static constexpr float StartingDistanceMultiplier = 1.75f; - static constexpr float StartingRotationAngle = Constants::QuarterPi / 2.0f; - - //! This flag is needed to wait one frame after each frame capture to reset FrameCaptureSystemComponent - bool m_readyToCapture = true; - //! This is necessary to suspend capture to allow a frame for Material and Mesh components to assign materials - int m_ticksToCapture = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp deleted file mode 100644 index 826ec4ae0d..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - FindThumbnailToRenderStep::FindThumbnailToRenderStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void FindThumbnailToRenderStep::Start() - { - TickBus::Handler::BusConnect(); - } - - void FindThumbnailToRenderStep::Stop() - { - TickBus::Handler::BusDisconnect(); - } - - void FindThumbnailToRenderStep::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) - { - PickNextThumbnail(); - } - - void FindThumbnailToRenderStep::PickNextThumbnail() - { - if (!m_context->GetData()->m_thumbnailQueue.empty()) - { - // pop the next thumbnailkey to be rendered from the queue - m_context->GetData()->m_thumbnailKeyRendered = m_context->GetData()->m_thumbnailQueue.front(); - m_context->GetData()->m_thumbnailQueue.pop(); - - // Find whether thumbnailkey contains a material asset or set a default material - m_context->GetData()->m_materialAsset = m_context->GetData()->m_defaultMaterialAsset; - Data::AssetId materialAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::MaterialAsset::RTTI_Type()); - if (materialAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(materialAssetId).second) - { - m_context->GetData()->m_materialAsset.Create(materialAssetId); - m_context->GetData()->m_materialAsset.QueueLoad(); - } - } - - // Find whether thumbnailkey contains a model asset or set a default model - m_context->GetData()->m_modelAsset = m_context->GetData()->m_defaultModelAsset; - Data::AssetId modelAssetId = GetAssetId(m_context->GetData()->m_thumbnailKeyRendered, RPI::ModelAsset::RTTI_Type()); - if (modelAssetId.IsValid()) - { - if (m_context->GetData()->m_assetsToLoad.emplace(modelAssetId).second) - { - m_context->GetData()->m_modelAsset.Create(modelAssetId); - m_context->GetData()->m_modelAsset.QueueLoad(); - } - } - - m_context->SetStep(Step::WaitForAssetsToLoad); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h deleted file mode 100644 index e63bc5dce5..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! FindThumbnailToRenderStep checks whether there are any new thumbnails that need to be rendered every tick - class FindThumbnailToRenderStep - : public ThumbnailRendererStep - , private TickBus::Handler - { - public: - FindThumbnailToRenderStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - void PickNextThumbnail(); - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp deleted file mode 100644 index 6f74627bee..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - InitializeStep::InitializeStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void InitializeStep::Start() - { - auto data = m_context->GetData(); - - data->m_entityContext = AZStd::make_unique(); - data->m_entityContext->InitContext(); - - // Create and register a scene with all required feature processors - RPI::SceneDescriptor sceneDesc; - - 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); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto* sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Thumbnail system failed to get scene system implementation."); - Outcome, AZStd::string> createSceneOutcome = - sceneSystem->CreateScene(data->m_sceneName); - AZ_Assert(createSceneOutcome, createSceneOutcome.GetError().c_str()); // This should never happen unless scene creation has changed. - data->m_frameworkScene = createSceneOutcome.TakeValue(); - data->m_frameworkScene->SetSubsystem(data->m_scene); - - data->m_frameworkScene->SetSubsystem(data->m_entityContext.get()); - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = data->m_pipelineName; - pipelineDesc.m_rootPassTemplate = "ThumbnailPipelineRenderToTexture"; - // We have to set the samples to 4 to match the pipeline passes' setting, otherwise it may lead to device lost issue - // [GFX TODO] [ATOM-13551] Default value sand validation required to prevent pipeline crash and device lost - pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; - data->m_renderPipeline = RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - data->m_scene->AddRenderPipeline(data->m_renderPipeline); - data->m_scene->Activate(); - RPI::RPISystemInterface::Get()->RegisterScene(data->m_scene); - data->m_passHierarchy.push_back(data->m_pipelineName); - data->m_passHierarchy.push_back("CopyToSwapChain"); - - // Connect camera to pipeline's default view after camera entity activated - Name viewName = Name("MainCamera"); - data->m_view = RPI::View::CreateView(viewName, RPI::View::UsageCamera); - - Matrix4x4 viewToClipMatrix; - MakePerspectiveFovMatrixRH(viewToClipMatrix, - Constants::QuarterPi, - AspectRatio, - NearDist, - FarDist, true); - data->m_view->SetViewToClipMatrix(viewToClipMatrix); - - data->m_renderPipeline->SetDefaultView(data->m_view); - - // Create lighting preset - data->m_lightingPresetAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(ThumbnailRendererData::LightingPresetPath); - if (data->m_lightingPresetAsset.IsReady()) - { - auto preset = data->m_lightingPresetAsset->GetDataAs(); - if (preset) - { - auto iblFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto postProcessFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(EntityId())->GetOrCreateExposureControlSettingsInterface(); - auto directionalLightFeatureProcessor = data->m_scene->GetFeatureProcessor(); - auto skyboxFeatureProcessor = data->m_scene->GetFeatureProcessor(); - skyboxFeatureProcessor->Enable(true); - skyboxFeatureProcessor->SetSkyboxMode(Render::SkyBoxMode::Cubemap); - - Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = Constants::HalfPi; - cameraConfig.m_nearClipDistance = NearDist; - cameraConfig.m_farClipDistance = FarDist; - cameraConfig.m_frustumWidth = 100.0f; - cameraConfig.m_frustumHeight = 100.0f; - - AZStd::vector lightHandles; - - preset->ApplyLightingPreset( - iblFeatureProcessor, - skyboxFeatureProcessor, - exposureControlSettingInterface, - directionalLightFeatureProcessor, - cameraConfig, - lightHandles); - } - } - - // Create preview model - AzFramework::EntityContextRequestBus::EventResult(data->m_modelEntity, data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ThumbnailPreviewModel"); - data->m_modelEntity->CreateComponent(Render::MeshComponentTypeId); - data->m_modelEntity->CreateComponent(Render::MaterialComponentTypeId); - data->m_modelEntity->CreateComponent(azrtti_typeid()); - data->m_modelEntity->Init(); - data->m_modelEntity->Activate(); - - // preload default model - Data::AssetId defaultModelAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultModelAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultModelPath, - RPI::ModelAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultModelAssetId.IsValid(), "Default model asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultModelPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultModelAssetId).second) - { - data->m_defaultModelAsset.Create(defaultModelAssetId); - data->m_defaultModelAsset.QueueLoad(); - } - - // preload default material - Data::AssetId defaultMaterialAssetId; - Data::AssetCatalogRequestBus::BroadcastResult( - defaultMaterialAssetId, - &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, - m_context->GetData()->DefaultMaterialPath, - RPI::MaterialAsset::RTTI_Type(), - false); - AZ_Error("ThumbnailRenderer", defaultMaterialAssetId.IsValid(), "Default material asset is invalid. Verify the asset %s exists.", m_context->GetData()->DefaultMaterialPath); - if (m_context->GetData()->m_assetsToLoad.emplace(defaultMaterialAssetId).second) - { - data->m_defaultMaterialAsset.Create(defaultMaterialAssetId); - data->m_defaultMaterialAsset.QueueLoad(); - } - - m_context->SetStep(Step::FindThumbnailToRender); - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h deleted file mode 100644 index cdac492e80..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! InitializeStep sets up RPI system and scene and prepares it for rendering thumbnail entities - //! This step is only called once when CommonThumbnailRenderer begins rendering its first thumbnail - class InitializeStep - : public ThumbnailRendererStep - { - public: - InitializeStep(ThumbnailRendererContext* context); - - void Start() override; - - private: - static constexpr float AspectRatio = 1.0f; - static constexpr float NearDist = 0.1f; - static constexpr float FarDist = 100.0f; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp deleted file mode 100644 index a14f48e408..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - ReleaseResourcesStep::ReleaseResourcesStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void ReleaseResourcesStep::Start() - { - auto data = m_context->GetData(); - - data->m_defaultMaterialAsset.Release(); - data->m_defaultModelAsset.Release(); - data->m_materialAsset.Release(); - data->m_modelAsset.Release(); - data->m_lightingPresetAsset.Release(); - - if (data->m_modelEntity) - { - AzFramework::EntityContextRequestBus::Event(data->m_entityContext->GetContextId(), - &AzFramework::EntityContextRequestBus::Events::DestroyEntity, data->m_modelEntity); - data->m_modelEntity = nullptr; - } - - data->m_scene->Deactivate(); - data->m_scene->RemoveRenderPipeline(data->m_renderPipeline->GetId()); - RPI::RPISystemInterface::Get()->UnregisterScene(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_scene); - data->m_frameworkScene->UnsetSubsystem(data->m_entityContext.get()); - data->m_scene = nullptr; - data->m_frameworkScene = nullptr; - data->m_renderPipeline = nullptr; - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h deleted file mode 100644 index 4858b90b96..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ReleaseResourcesStep - : public ThumbnailRendererStep - { - public: - ReleaseResourcesStep(ThumbnailRendererContext* context); - - void Start() override; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h deleted file mode 100644 index cc10f91525..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - class ThumbnailRendererContext; - - //! ThumbnailRendererStep decouples CommonThumbnailRenderer logic into easy-to-understand and debug pieces - class ThumbnailRendererStep - { - public: - explicit ThumbnailRendererStep(ThumbnailRendererContext* context) : m_context(context) {} - virtual ~ThumbnailRendererStep() = default; - - //! Start is called when step begins execution - virtual void Start() {} - //! Stop is called when step ends execution - virtual void Stop() {} - - protected: - ThumbnailRendererContext* m_context; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ - diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp deleted file mode 100644 index 4f32bc4b68..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "Thumbnails/ThumbnailerBus.h" - -#include -#include -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - WaitForAssetsToLoadStep::WaitForAssetsToLoadStep(ThumbnailRendererContext* context) - : ThumbnailRendererStep(context) - { - } - - void WaitForAssetsToLoadStep::Start() - { - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::Stop() - { - Data::AssetBus::Handler::BusDisconnect(); - TickBus::Handler::BusDisconnect(); - m_context->GetData()->m_assetsToLoad.clear(); - } - - void WaitForAssetsToLoadStep::LoadNextAsset() - { - if (m_context->GetData()->m_assetsToLoad.empty()) - { - // When all assets are loaded, render the thumbnail itself - m_context->SetStep(Step::Capture); - } - else - { - // Pick the the next asset and wait until its ready - const auto assetIdIt = m_context->GetData()->m_assetsToLoad.begin(); - m_context->GetData()->m_assetsToLoad.erase(assetIdIt); - m_assetId = *assetIdIt; - Data::AssetBus::Handler::BusConnect(m_assetId); - // If asset is already loaded, then AssetEvents will call OnAssetReady instantly and we don't need to wait this time - if (Data::AssetBus::Handler::BusIsConnected()) - { - TickBus::Handler::BusConnect(); - m_timeRemainingS = TimeOutS; - } - } - } - - void WaitForAssetsToLoadStep::OnAssetReady([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - LoadNextAsset(); - } - - void WaitForAssetsToLoadStep::OnAssetError([[maybe_unused]] Data::Asset asset) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnAssetCanceled([[maybe_unused]] Data::AssetId assetId) - { - Data::AssetBus::Handler::BusDisconnect(); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - - void WaitForAssetsToLoadStep::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_timeRemainingS -= deltaTime; - if (m_timeRemainingS < 0) - { - auto assetIdStr = m_assetId.ToString(); - AZ_Warning("CommonThumbnailRenderer", false, "Timed out waiting for asset %s to load.", assetIdStr.c_str()); - AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event( - m_context->GetData()->m_thumbnailKeyRendered, - &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender); - m_context->SetStep(Step::FindThumbnailToRender); - } - } - } // namespace Thumbnails - } // namespace LyIntegration -} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h deleted file mode 100644 index 921d1511ca..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - namespace LyIntegration - { - namespace Thumbnails - { - //! WaitForAssetsToLoadStep pauses further rendering until all assets used for rendering a thumbnail have been loaded - class WaitForAssetsToLoadStep - : public ThumbnailRendererStep - , private Data::AssetBus::Handler - , private TickBus::Handler - { - public: - WaitForAssetsToLoadStep(ThumbnailRendererContext* context); - - void Start() override; - void Stop() override; - - private: - void LoadNextAsset(); - - // AZ::Data::AssetBus::Handler - void OnAssetReady(Data::Asset asset) override; - void OnAssetError(Data::Asset asset) override; - void OnAssetCanceled(Data::AssetId assetId) override; - - //! AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - static constexpr float TimeOutS = 3.0f; - Data::AssetId m_assetId; - float m_timeRemainingS = 0; - }; - } // namespace Thumbnails - } // namespace LyIntegration -} // 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 174eb30b31..2714b65a56 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -7,9 +7,9 @@ # set(FILES + Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h 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 @@ -45,8 +45,6 @@ set(FILES Source/Material/EditorMaterialSystemComponent.h Source/Material/MaterialBrowserInteractions.h Source/Material/MaterialBrowserInteractions.cpp - Source/Material/MaterialThumbnail.cpp - Source/Material/MaterialThumbnail.h Source/Mesh/EditorMeshComponent.h Source/Mesh/EditorMeshComponent.cpp Source/Mesh/EditorMeshStats.h @@ -55,8 +53,6 @@ set(FILES Source/Mesh/EditorMeshSystemComponent.h Source/Mesh/EditorMeshStatsSerializer.cpp Source/Mesh/EditorMeshStatsSerializer.h - Source/Mesh/MeshThumbnail.h - Source/Mesh/MeshThumbnail.cpp Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.h Source/OcclusionCullingPlane/EditorOcclusionCullingPlaneComponent.cpp Source/PostProcess/EditorPostFxLayerComponent.cpp @@ -95,28 +91,19 @@ set(FILES Source/SkyBox/EditorHDRiSkyboxComponent.h Source/SkyBox/EditorPhysicalSkyComponent.cpp Source/SkyBox/EditorPhysicalSkyComponent.h - Source/Thumbnails/ThumbnailUtils.h - Source/Thumbnails/ThumbnailUtils.cpp - Source/Thumbnails/Preview/CommonPreviewer.cpp - Source/Thumbnails/Preview/CommonPreviewer.h - Source/Thumbnails/Preview/CommonPreviewer.ui - Source/Thumbnails/Preview/CommonPreviewerFactory.cpp - Source/Thumbnails/Preview/CommonPreviewerFactory.h - Source/Thumbnails/Rendering/CommonThumbnailRenderer.cpp - Source/Thumbnails/Rendering/CommonThumbnailRenderer.h - Source/Thumbnails/Rendering/ThumbnailRendererData.h - Source/Thumbnails/Rendering/ThumbnailRendererContext.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ThumbnailRendererStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/FindThumbnailToRenderStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/WaitForAssetsToLoadStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/CaptureStep.h - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.cpp - Source/Thumbnails/Rendering/ThumbnailRendererSteps/ReleaseResourcesStep.h + Source/SharedPreview/SharedPreviewer.cpp + Source/SharedPreview/SharedPreviewer.h + Source/SharedPreview/SharedPreviewer.ui + Source/SharedPreview/SharedPreviewerFactory.cpp + Source/SharedPreview/SharedPreviewerFactory.h + Source/SharedPreview/SharedPreviewContent.cpp + Source/SharedPreview/SharedPreviewContent.h + Source/SharedPreview/SharedPreviewUtils.cpp + Source/SharedPreview/SharedPreviewUtils.h + Source/SharedPreview/SharedThumbnail.cpp + Source/SharedPreview/SharedThumbnail.h + Source/SharedPreview/SharedThumbnailRenderer.cpp + Source/SharedPreview/SharedThumbnailRenderer.h Source/Scripting/EditorEntityReferenceComponent.cpp Source/Scripting/EditorEntityReferenceComponent.h Source/SurfaceData/EditorSurfaceDataMeshComponent.cpp