Restore Editor viewport icon rendering (#879)
This introduces an EditorViewportIconDisplayInterface that will eventually be used to outright remove CIconManager, it provides a simple interface for loading 2D image assets and rendering them on-screen. It also introduces AtomBridge::PerViewportDynamicDraw for getting a dynamic draw instance on a per-viewport basis
This commit is contained in:
committed by
GitHub
parent
dc0f1ff0b1
commit
d1863c6c5b
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! An interface for loading simple icon assets and rendering them to screen on a per-viewport basis.
|
||||
class EditorViewportIconDisplayInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(EditorViewportIconDisplayInterface, "{D5190B58-2561-4F3F-B793-F1E7D454CDF2}");
|
||||
|
||||
using IconId = AZ::s32;
|
||||
static constexpr IconId InvalidIconId = -1;
|
||||
|
||||
enum class CoordinateSpace : AZ::u8
|
||||
{
|
||||
ScreenSpace,
|
||||
WorldSpace
|
||||
};
|
||||
|
||||
//! These draw parameters control rendering for a single icon to a single viewport.
|
||||
struct DrawParameters
|
||||
{
|
||||
//! The ViewportId to render to.
|
||||
AzFramework::ViewportId m_viewport = AzFramework::InvalidViewportId;
|
||||
//! The icon ID, retrieved from GetOrLoadIconForPath, to render to screen.
|
||||
IconId m_icon = InvalidIconId;
|
||||
//! The color, including opacity, to render the icon with. White will render the icon as opaque in its original color.
|
||||
AZ::Color m_color = AZ::Colors::White;
|
||||
//! The position to render the icon to, in world or screen space depending on m_positionSpace.
|
||||
AZ::Vector3 m_position;
|
||||
//! The coordinate system to use for m_position.
|
||||
//! ScreenSpace will accept m_position in the form of [X, Y, Depth], where X & Y are screen coordinates in
|
||||
//! pixels and Depth is a z-ordering depth value from 0.0f to 1.0f.
|
||||
//! WorldSpace will accept a 3D vector in world space coordinates that will be translated back into screen
|
||||
//! space when the icon is rendered.
|
||||
CoordinateSpace m_positionSpace = CoordinateSpace::ScreenSpace;
|
||||
//! The size to render the icon as, in pixels.
|
||||
AZ::Vector2 m_size;
|
||||
};
|
||||
|
||||
//! The current load status of an icon retrieved by GetOrLoadIconForPath.
|
||||
enum class IconLoadStatus : AZ::u8
|
||||
{
|
||||
Unloaded,
|
||||
Loading,
|
||||
Loaded,
|
||||
Error
|
||||
};
|
||||
|
||||
//! Draws an icon to a viewport given a set of draw parameters.
|
||||
//! Requires an IconId retrieved from GetOrLoadIconForPath.
|
||||
virtual void DrawIcon(const DrawParameters& drawParameters) = 0;
|
||||
//! Retrieves a reusable IconId for an icon at a given path.
|
||||
//! This will load the icon, if it has not already been loaded.
|
||||
//! @param path should be a relative asset path to an icon image asset.
|
||||
//! png and svg icons are currently supported.
|
||||
virtual IconId GetOrLoadIconForPath(AZStd::string_view path) = 0;
|
||||
//! Gets the current load status of an icon retrieved via GetOrLoadIconForPath.
|
||||
virtual IconLoadStatus GetIconLoadStatus(IconId icon) = 0;
|
||||
};
|
||||
|
||||
using EditorViewportIconDisplay = AZ::Interface<EditorViewportIconDisplayInterface>;
|
||||
} //namespace AzToolsFramework
|
||||
+2
-2
@@ -17,6 +17,7 @@
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
|
||||
@@ -313,8 +314,7 @@ namespace AzToolsFramework
|
||||
// if we do not yet have a valid texture id, request it using the entity icon path
|
||||
if (m_entityIconTextureId == 0)
|
||||
{
|
||||
EditorRequestBus::BroadcastResult(
|
||||
m_entityIconTextureId, &EditorRequests::GetIconTextureIdFromEntityIconPath, m_entityIconPath);
|
||||
m_entityIconTextureId = EditorViewportIconDisplay::Get()->GetOrLoadIconForPath(m_entityIconPath);
|
||||
}
|
||||
|
||||
return m_entityIconTextureId;
|
||||
|
||||
+9
-4
@@ -21,6 +21,7 @@
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
|
||||
AZ_CVAR(
|
||||
bool, ed_visibility_showAggregateEntitySelectionBounds, false, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
@@ -232,10 +233,14 @@ namespace AzToolsFramework
|
||||
return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}();
|
||||
|
||||
debugDisplay.SetColor(iconHighlight);
|
||||
// debugDisplay.DrawTextureLabel(
|
||||
// iconTextureId, entityPosition, iconSize, iconSize,
|
||||
// /*DisplayContext::ETextureIconFlags::TEXICON_ON_TOP=*/ 0x0008);
|
||||
EditorViewportIconDisplay::Get()->DrawIcon({
|
||||
viewportInfo.m_viewportId,
|
||||
iconTextureId,
|
||||
iconHighlight,
|
||||
entityPosition,
|
||||
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace,
|
||||
AZ::Vector2{iconSize, iconSize}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ set(FILES
|
||||
API/EditorWindowRequestBus.h
|
||||
API/EntityCompositionRequestBus.h
|
||||
API/EntityCompositionNotificationBus.h
|
||||
API/EditorViewportIconDisplayInterface.h
|
||||
API/ViewPaneOptions.h
|
||||
Application/Ticker.h
|
||||
Application/Ticker.cpp
|
||||
|
||||
@@ -87,6 +87,14 @@ namespace AZ
|
||||
//! Finalize and validate initialization. Any initialization functions should be called before EndInit is called.
|
||||
void EndInit();
|
||||
|
||||
//! Set up the DynamicDrawContext for the input Scene.
|
||||
//! This should be called after the last frame is done and before any draw calls.
|
||||
void SetScene(Scene* scene);
|
||||
|
||||
//! Set up the DynamicDrawContext for the input RenderPipeline.
|
||||
//! This should be called after the last frame is done and before any draw calls.
|
||||
void SetRenderPipeline(RenderPipeline* pipeline);
|
||||
|
||||
//! Return if this DynamicDrawContext is ready to add draw calls
|
||||
bool IsReady();
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace AZ
|
||||
class ViewportContextManager;
|
||||
|
||||
//! ViewportContext wraps a native window and represents a minimal viewport
|
||||
//! in which a scene is rendered on-screen
|
||||
//! in which a scene is rendered on-screen.
|
||||
//! ViewportContexts are registered on creation to allow consumers to listen to notifications
|
||||
//! and manage the view stack for a given viewport
|
||||
//! and manage the view stack for a given viewport.
|
||||
class ViewportContext
|
||||
: public SceneNotificationBus::Handler
|
||||
, public AzFramework::WindowNotificationBus::Handler
|
||||
@@ -61,11 +61,11 @@ namespace AZ
|
||||
|
||||
//! Gets the current name of this ViewportContext.
|
||||
//! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be
|
||||
//! renamed via AZ::Interface<ViewportContextRequestsInterface>::Get()->RenameViewportContext.
|
||||
//! renamed via AZ::RPI::ViewportContextRequests::Get()->RenameViewportContext(...).
|
||||
AZ::Name GetName() const;
|
||||
|
||||
//! Gets the default view associated with this ViewportContext.
|
||||
//! Alternatively, use AZ::Interface<ViewportContextRequestsInterface>::Get()->GetCurrentView.
|
||||
//! Alternatively, use AZ::RPI::ViewportContextRequests::Get()->GetCurrentView().
|
||||
ViewPtr GetDefaultView();
|
||||
ConstViewPtr GetDefaultView() const;
|
||||
|
||||
@@ -99,6 +99,18 @@ namespace AZ
|
||||
//! Notifies consumers when the render scene has changed.
|
||||
void ConnectSceneChangedHandler(SceneChangedEvent::Handler& handler);
|
||||
|
||||
using PipelineChangedEvent = AZ::Event<RenderPipelinePtr>;
|
||||
//! Notifies consumers when the current pipeline associated with our window has changed.
|
||||
void ConnectCurrentPipelineChangedHandler(PipelineChangedEvent::Handler& handler);
|
||||
|
||||
using ViewChangedEvent = AZ::Event<ViewPtr>;
|
||||
//! Notifies consumers when the default view has changed.
|
||||
void ConnectDefaultViewChangedHandler(ViewChangedEvent::Handler& handler);
|
||||
|
||||
using ViewportIdEvent = AZ::Event<AzFramework::ViewportId>;
|
||||
//! Notifies consumers when this ViewportContext is about to be destroyed.
|
||||
void ConnectAboutToBeDestroyedHandler(ViewportIdEvent::Handler& handler);
|
||||
|
||||
// ViewportRequestBus interface
|
||||
//! Gets the current camera's view matrix.
|
||||
const AZ::Matrix4x4& GetCameraViewMatrix() const override;
|
||||
@@ -123,12 +135,17 @@ namespace AZ
|
||||
WindowContextSharedPtr m_windowContext;
|
||||
ViewPtr m_defaultView;
|
||||
AzFramework::WindowSize m_viewportSize;
|
||||
|
||||
SizeChangedEvent m_sizeChangedEvent;
|
||||
MatrixChangedEvent m_viewMatrixChangedEvent;
|
||||
MatrixChangedEvent::Handler m_onViewMatrixChangedHandler;
|
||||
MatrixChangedEvent m_projectionMatrixChangedEvent;
|
||||
MatrixChangedEvent::Handler m_onProjectionMatrixChangedHandler;
|
||||
SceneChangedEvent m_sceneChangedEvent;
|
||||
PipelineChangedEvent m_currentPipelineChangedEvent;
|
||||
ViewChangedEvent m_defaultViewChangedEvent;
|
||||
ViewportIdEvent m_aboutToBeDestroyedEvent;
|
||||
|
||||
ViewportContextManager* m_manager;
|
||||
RenderPipelinePtr m_currentPipeline;
|
||||
Name m_name;
|
||||
|
||||
@@ -211,6 +211,42 @@ namespace AZ
|
||||
m_rhiPipelineState = m_pipelineState->GetRHIPipelineState();
|
||||
}
|
||||
|
||||
void DynamicDrawContext::SetScene(Scene* scene)
|
||||
{
|
||||
AZ_Assert(scene, "SetScene called with an invalid scene");
|
||||
if (!scene || m_scene == scene)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_scene = scene;
|
||||
m_drawFilter = RHI::DrawFilterMaskDefaultValue;
|
||||
// Reinitialize if it was initialized
|
||||
if (m_initialized)
|
||||
{
|
||||
// Report warning if there were some draw data
|
||||
AZ_Warning(
|
||||
"DynamicDrawContext", m_cachedDrawItems.size() == 0,
|
||||
"DynamicDrawContext::SetForScene should be called"
|
||||
" when there is no cached draw data");
|
||||
// Clear some cached data
|
||||
FrameEnd();
|
||||
m_cachedRhiPipelineStates.clear();
|
||||
// Reinitialize
|
||||
EndInit();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicDrawContext::SetRenderPipeline(RenderPipeline* pipeline)
|
||||
{
|
||||
AZ_Assert(pipeline, "SetRenderPipeline called with an invalid pipeline");
|
||||
if (!pipeline)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetScene(pipeline->GetScene());
|
||||
m_drawFilter = pipeline->GetDrawFilterMask();
|
||||
}
|
||||
|
||||
bool DynamicDrawContext::IsReady()
|
||||
{
|
||||
return m_initialized;
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace AZ
|
||||
|
||||
ViewportContext::~ViewportContext()
|
||||
{
|
||||
m_aboutToBeDestroyedEvent.Signal(m_id);
|
||||
|
||||
AzFramework::WindowNotificationBus::Handler::BusDisconnect();
|
||||
AzFramework::ViewportRequestBus::Handler::BusDisconnect();
|
||||
|
||||
@@ -171,6 +173,21 @@ namespace AZ
|
||||
handler.Connect(m_sceneChangedEvent);
|
||||
}
|
||||
|
||||
void ViewportContext::ConnectCurrentPipelineChangedHandler(PipelineChangedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_currentPipelineChangedEvent);
|
||||
}
|
||||
|
||||
void ViewportContext::ConnectDefaultViewChangedHandler(ViewChangedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_defaultViewChangedEvent);
|
||||
}
|
||||
|
||||
void ViewportContext::ConnectAboutToBeDestroyedHandler(ViewportIdEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_aboutToBeDestroyedEvent);
|
||||
}
|
||||
|
||||
const AZ::Matrix4x4& ViewportContext::GetCameraViewMatrix() const
|
||||
{
|
||||
return GetDefaultView()->GetWorldToViewMatrix();
|
||||
@@ -214,6 +231,7 @@ namespace AZ
|
||||
m_defaultView = view;
|
||||
UpdatePipelineView();
|
||||
|
||||
m_defaultViewChangedEvent.Signal(view);
|
||||
m_viewMatrixChangedEvent.Signal(view->GetWorldToViewMatrix());
|
||||
m_projectionMatrixChangedEvent.Signal(view->GetViewToClipMatrix());
|
||||
|
||||
@@ -232,6 +250,7 @@ namespace AZ
|
||||
if (!m_currentPipeline)
|
||||
{
|
||||
m_currentPipeline = m_rootScene ? m_rootScene->FindRenderPipelineForWindow(m_windowContext->GetWindowHandle()) : nullptr;
|
||||
m_currentPipelineChangedEvent.Signal(m_currentPipeline);
|
||||
}
|
||||
|
||||
if (auto pipeline = GetCurrentPipeline())
|
||||
|
||||
@@ -106,5 +106,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
Gem::AtomFont
|
||||
Gem::AtomToolsFramework.Editor
|
||||
Gem::AtomViewportDisplayInfo
|
||||
Gem::AtomViewportDisplayIcons.Editor
|
||||
)
|
||||
endif()
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
|
||||
namespace AZ::AtomBridge
|
||||
{
|
||||
//! A simple interface for allocating a DynamicDrawContext on-demand for every viewport, based on
|
||||
//! a registered initialization function.
|
||||
class PerViewportDynamicDrawInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PerViewportDynamicDrawInterface, "{1FF054F5-55FF-4ADB-A86D-640B15FA0395}");
|
||||
|
||||
using DrawContextFactory = AZStd::function<void(RHI::Ptr<RPI::DynamicDrawContext>)>;
|
||||
//! Register a named dynamic draw context that can be retrieved on a per-viewport basis.
|
||||
//! GetNamedDynamicDraw context can be called on a registered context name to retrieve a
|
||||
//! valid DynamicDrawContext for a given viewport.
|
||||
virtual void RegisterDynamicDrawContext(AZ::Name name, DrawContextFactory contextInitializer) = 0;
|
||||
|
||||
//! Unregister a previously registered named per-viewport dynamic draw context.
|
||||
//! This will dispose of all dynamic draw contexts currently associated with this name.
|
||||
virtual void UnregisterDynamicDrawContext(AZ::Name name) = 0;
|
||||
|
||||
//! Get a dynamic draw context associated with the specified viewport based on a factory registered with
|
||||
//! RegisterNamedDynamicDrawContext. This dynamic draw context will be created if it does not already exist.
|
||||
virtual RHI::Ptr<RPI::DynamicDrawContext> GetDynamicDrawContextForViewport(AZ::Name name, AzFramework::ViewportId viewportId) = 0;
|
||||
};
|
||||
|
||||
using PerViewportDynamicDraw = AZ::Interface<PerViewportDynamicDrawInterface>;
|
||||
} // namespace AZ::AtomBridge
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <AtomBridgeSystemComponent.h>
|
||||
#include <AtomDebugDisplayViewportInterface.h>
|
||||
#include <FlyCameraInputComponent.h>
|
||||
#include <PerViewportDynamicDrawManager.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
@@ -104,10 +105,12 @@ namespace AZ
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(m_entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
|
||||
m_dynamicDrawManager = AZStd::make_unique<PerViewportDynamicDrawManager>();
|
||||
}
|
||||
|
||||
void AtomBridgeSystemComponent::Deactivate()
|
||||
{
|
||||
m_dynamicDrawManager.reset();
|
||||
AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect();
|
||||
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
|
||||
// Check if scene is emptry since scene might be released already when running AtomSampleViewer
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace AZ
|
||||
{
|
||||
// forward declares
|
||||
class AtomDebugDisplayViewportInterface;
|
||||
class PerViewportDynamicDrawManager;
|
||||
|
||||
class AtomBridgeSystemComponent
|
||||
: public Component
|
||||
@@ -82,6 +83,7 @@ namespace AZ
|
||||
RPI::ViewPtr m_view = nullptr;
|
||||
|
||||
AZStd::unordered_map<AzFramework::ViewportId, AZStd::shared_ptr<AtomDebugDisplayViewportInterface> > m_activeViewportsList;
|
||||
AZStd::unique_ptr<PerViewportDynamicDrawManager> m_dynamicDrawManager;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PerViewportDynamicDrawManager.h"
|
||||
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
|
||||
namespace AZ::AtomBridge
|
||||
{
|
||||
PerViewportDynamicDrawManager::PerViewportDynamicDrawManager()
|
||||
{
|
||||
PerViewportDynamicDraw::Register(this);
|
||||
}
|
||||
|
||||
PerViewportDynamicDrawManager::~PerViewportDynamicDrawManager()
|
||||
{
|
||||
PerViewportDynamicDraw::Unregister(this);
|
||||
}
|
||||
|
||||
void PerViewportDynamicDrawManager::RegisterDynamicDrawContext(AZ::Name name, DrawContextFactory contextInitializer)
|
||||
{
|
||||
AZStd::lock_guard lock(m_mutexDrawContexts);
|
||||
|
||||
const bool alreadyRegistered = m_registeredDrawContexts.find(name) != m_registeredDrawContexts.end();
|
||||
AZ_Error("AtomBridge", !alreadyRegistered, "Attempted to call RegisterDynamicDrawContext for already registered name: \"%s\"", name.GetCStr());
|
||||
if (alreadyRegistered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_registeredDrawContexts[name] = contextInitializer;
|
||||
}
|
||||
|
||||
void PerViewportDynamicDrawManager::UnregisterDynamicDrawContext(AZ::Name name)
|
||||
{
|
||||
AZStd::lock_guard lock(m_mutexDrawContexts);
|
||||
|
||||
auto drawContextFactoryIt = m_registeredDrawContexts.find(name);
|
||||
const bool registered = drawContextFactoryIt != m_registeredDrawContexts.end();
|
||||
AZ_Error("AtomBridge", registered, "Attempted to call UnregisterDynamicDrawContext for unregistered name: \"%s\"", name.GetCStr());
|
||||
if (!registered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_registeredDrawContexts.erase(drawContextFactoryIt);
|
||||
|
||||
for (auto& viewportData : m_viewportData)
|
||||
{
|
||||
viewportData.second.m_dynamicDrawContexts.erase(name);
|
||||
}
|
||||
}
|
||||
|
||||
RHI::Ptr<RPI::DynamicDrawContext> PerViewportDynamicDrawManager::GetDynamicDrawContextForViewport(
|
||||
AZ::Name name, AzFramework::ViewportId viewportId)
|
||||
{
|
||||
AZStd::lock_guard lock(m_mutexDrawContexts);
|
||||
|
||||
auto contextFactoryIt = m_registeredDrawContexts.find(name);
|
||||
if (contextFactoryIt == m_registeredDrawContexts.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto viewportContextManager = RPI::ViewportContextRequests::Get();
|
||||
RPI::ViewportContextPtr viewportContext = viewportContextManager->GetViewportContextById(viewportId);
|
||||
if (viewportContext == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get or create a ViewportData if one doesn't already exist
|
||||
ViewportData& viewportData = m_viewportData[viewportId];
|
||||
if (!viewportData.m_initialized)
|
||||
{
|
||||
viewportData.m_pipelineChangedHandler = AZ::Event<RPI::RenderPipelinePtr>::Handler([this, viewportId](RPI::RenderPipelinePtr pipeline)
|
||||
{
|
||||
AZStd::lock_guard lock(m_mutexDrawContexts);
|
||||
ViewportData& viewportData = m_viewportData[viewportId];
|
||||
for (auto& context : viewportData.m_dynamicDrawContexts)
|
||||
{
|
||||
context.second->SetRenderPipeline(pipeline.get());
|
||||
}
|
||||
});
|
||||
viewportData.m_viewportDestroyedHandler = AZ::Event<AzFramework::ViewportId>::Handler([this, viewportId](AzFramework::ViewportId id)
|
||||
{
|
||||
AZStd::lock_guard lock(m_mutexDrawContexts);
|
||||
m_viewportData.erase(id);
|
||||
});
|
||||
|
||||
viewportContext->ConnectCurrentPipelineChangedHandler(viewportData.m_pipelineChangedHandler);
|
||||
viewportContext->ConnectAboutToBeDestroyedHandler(viewportData.m_viewportDestroyedHandler);
|
||||
|
||||
viewportData.m_initialized = true;
|
||||
}
|
||||
|
||||
RHI::Ptr<RPI::DynamicDrawContext>& context = viewportData.m_dynamicDrawContexts[name];
|
||||
if (context == nullptr)
|
||||
{
|
||||
auto pipeline = viewportContext->GetCurrentPipeline().get();
|
||||
if (pipeline == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
context = RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(pipeline);
|
||||
contextFactoryIt->second(context);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
} //namespace AZ::AtomBridge
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AtomBridge/PerViewportDynamicDrawInterface.h>
|
||||
|
||||
namespace AZ::AtomBridge
|
||||
{
|
||||
class PerViewportDynamicDrawManager final : public PerViewportDynamicDrawInterface
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(PerViewportDynamicDrawManager, "{BED66185-00A7-43F7-BD28-C56BC8E4C535}");
|
||||
|
||||
PerViewportDynamicDrawManager();
|
||||
~PerViewportDynamicDrawManager();
|
||||
|
||||
// PerViewportDynamicDrawInterface overrides...
|
||||
void RegisterDynamicDrawContext(AZ::Name name, DrawContextFactory contextInitializer) override;
|
||||
void UnregisterDynamicDrawContext(AZ::Name name) override;
|
||||
RHI::Ptr<RPI::DynamicDrawContext> GetDynamicDrawContextForViewport(AZ::Name name, AzFramework::ViewportId viewportId) override;
|
||||
|
||||
private:
|
||||
struct ViewportData
|
||||
{
|
||||
AZStd::unordered_map<AZ::Name, RHI::Ptr<RPI::DynamicDrawContext>> m_dynamicDrawContexts;
|
||||
|
||||
// Event handlers
|
||||
AZ::Event<RPI::RenderPipelinePtr>::Handler m_pipelineChangedHandler;
|
||||
AZ::Event<AzFramework::ViewportId>::Handler m_viewportDestroyedHandler;
|
||||
|
||||
// Cached state
|
||||
bool m_initialized = false;
|
||||
};
|
||||
AZStd::map<AzFramework::ViewportId, ViewportData> m_viewportData;
|
||||
AZStd::unordered_map<AZ::Name, DrawContextFactory> m_registeredDrawContexts;
|
||||
AZStd::mutex m_mutexDrawContexts;
|
||||
};
|
||||
} //namespace AZ::AtomBridge
|
||||
@@ -12,10 +12,13 @@
|
||||
set(FILES
|
||||
Include/AtomBridge/AtomBridgeBus.h
|
||||
Include/AtomBridge/FlyCameraInputBus.h
|
||||
Include/AtomBridge/PerViewportDynamicDrawInterface.h
|
||||
Source/AtomBridgeSystemComponent.cpp
|
||||
Source/AtomBridgeSystemComponent.h
|
||||
Source/FlyCameraInputComponent.cpp
|
||||
Source/FlyCameraInputComponent.h
|
||||
Source/AtomDebugDisplayViewportInterface.cpp
|
||||
Source/AtomDebugDisplayViewportInterface.h
|
||||
Source/FlyCameraInputComponent.cpp
|
||||
Source/FlyCameraInputComponent.h
|
||||
Source/PerViewportDynamicDrawManager.cpp
|
||||
Source/PerViewportDynamicDrawManager.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
|
||||
ShaderResourceGroup InstanceSrg : SRG_PerDraw
|
||||
{
|
||||
float2 m_viewportSize;
|
||||
Texture2D m_texture;
|
||||
|
||||
Sampler m_sampler
|
||||
{
|
||||
MaxAnisotropy = 16;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
AddressW = Clamp;
|
||||
};
|
||||
};
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
float3 m_position : POSITION;
|
||||
float4 m_color : COLOR0;
|
||||
float2 m_uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
float4 m_position : SV_Position;
|
||||
float4 m_color : COLOR0;
|
||||
float2 m_uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
VSOutput MainVS(VSInput IN)
|
||||
{
|
||||
// Convert from screen space to clip space
|
||||
float2 posXY = float2(IN.m_position.xy) / InstanceSrg::m_viewportSize * 2.0f - float2(1.0f, 1.0f);
|
||||
posXY.y *= -1.0f;
|
||||
float4 posPS = float4(posXY, IN.m_position.z, 1.0f);
|
||||
|
||||
VSOutput OUT;
|
||||
OUT.m_position = posPS;
|
||||
OUT.m_color = IN.m_color;
|
||||
OUT.m_uv = IN.m_uv;
|
||||
return OUT;
|
||||
};
|
||||
|
||||
struct PSOutput
|
||||
{
|
||||
float4 m_color : SV_Target0;
|
||||
};
|
||||
|
||||
PSOutput MainPS(VSOutput IN)
|
||||
{
|
||||
PSOutput OUT;
|
||||
|
||||
float4 tex;
|
||||
|
||||
tex = InstanceSrg::m_texture.Sample(InstanceSrg::m_sampler, IN.m_uv);
|
||||
float opacity = IN.m_color.a * tex.a;
|
||||
|
||||
// We use pre-multiplied alpha here since it is more flexible. For example, it enables alpha-blended rendering to
|
||||
// a render target and then alpha blending that render target into another render target
|
||||
OUT.m_color.rgb = IN.m_color.rgb * tex.rgb * opacity;
|
||||
|
||||
OUT.m_color.a = opacity;
|
||||
return OUT;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"Source" : "TexturedIcon",
|
||||
|
||||
"DepthStencilState" : {
|
||||
"Depth" : {
|
||||
"Enable" : false,
|
||||
"CompareFunc" : "Always"
|
||||
}
|
||||
},
|
||||
|
||||
"RasterState" : {
|
||||
"DepthClipEnable" : false,
|
||||
"CullMode" : "None"
|
||||
},
|
||||
|
||||
"BlendState" : {
|
||||
"Enable" : true,
|
||||
"BlendSource" : "One",
|
||||
"BlendDest" : "AlphaSourceInverse",
|
||||
"BlendOp" : "Add"
|
||||
},
|
||||
|
||||
"DrawList" : "2dpass",
|
||||
|
||||
"ProgramSettings":
|
||||
{
|
||||
"EntryPoints":
|
||||
[
|
||||
{
|
||||
"name": "MainVS",
|
||||
"type": "Vertex"
|
||||
},
|
||||
{
|
||||
"name": "MainPS",
|
||||
"type": "Fragment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
add_subdirectory(Code)
|
||||
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
ly_add_target(
|
||||
NAME AtomViewportDisplayIcons.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
atomviewportdisplayicons_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzFramework
|
||||
AZ::AzToolsFramework
|
||||
AZ::AtomCore
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Gui
|
||||
3rdParty::Qt::Svg
|
||||
Gem::Atom_RHI.Reflect
|
||||
Gem::Atom_RPI.Public
|
||||
Gem::Atom_Bootstrap.Headers
|
||||
Gem::Atom_AtomBridge.Static
|
||||
)
|
||||
endif()
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "AtomViewportDisplayIconsSystemComponent.h"
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAssetCreator.h>
|
||||
#include <Atom/RPI.Reflect/Image/ImageMipChainAssetCreator.h>
|
||||
#include <Atom/RPI.Public/Image/StreamingImagePool.h>
|
||||
|
||||
#include <AtomBridge/PerViewportDynamicDrawInterface.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
namespace AZ::Render
|
||||
{
|
||||
void AtomViewportDisplayIconsSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AtomViewportDisplayIconsSystemComponent, AZ::Component>()
|
||||
->Version(0)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<AtomViewportDisplayIconsSystemComponent>("Viewport Display Icons", "Provides an interface for drawing simple icons to the Editor viewport")
|
||||
->ClassElement(Edit::ClassElements::EditorData, "")
|
||||
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
->Attribute(Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("ViewportDisplayIconsService"));
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("ViewportDisplayIconsService"));
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
|
||||
required.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::Activate()
|
||||
{
|
||||
AzToolsFramework::EditorViewportIconDisplay::Register(this);
|
||||
|
||||
Bootstrap::NotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::Deactivate()
|
||||
{
|
||||
Bootstrap::NotificationBus::Handler::BusDisconnect();
|
||||
|
||||
auto perViewportDynamicDrawInterface = AtomBridge::PerViewportDynamicDraw::Get();
|
||||
if (!perViewportDynamicDrawInterface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (perViewportDynamicDrawInterface)
|
||||
{
|
||||
perViewportDynamicDrawInterface->UnregisterDynamicDrawContext(m_drawContextName);
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorViewportIconDisplay::Unregister(this);
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::DrawIcon(const DrawParameters& drawParameters)
|
||||
{
|
||||
// Ensure we have a valid viewport context & dynamic draw interface
|
||||
auto viewportContext = RPI::ViewportContextRequests::Get()->GetViewportContextById(drawParameters.m_viewport);
|
||||
if (viewportContext == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto perViewportDynamicDrawInterface =
|
||||
AtomBridge::PerViewportDynamicDraw::Get();
|
||||
if (!perViewportDynamicDrawInterface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RHI::Ptr<RPI::DynamicDrawContext> dynamicDraw =
|
||||
perViewportDynamicDrawInterface->GetDynamicDrawContextForViewport(m_drawContextName, drawParameters.m_viewport);
|
||||
if (dynamicDraw == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find our icon, falling back on a grey placeholder if its image is unavailable
|
||||
AZ::Data::Instance<AZ::RPI::Image> image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Grey);
|
||||
if (auto iconIt = m_iconData.find(drawParameters.m_icon); iconIt != m_iconData.end())
|
||||
{
|
||||
auto& iconData = iconIt->second;
|
||||
if (iconData.m_image)
|
||||
{
|
||||
image = iconData.m_image;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize our shader
|
||||
auto viewportSize = viewportContext->GetViewportSize();
|
||||
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
|
||||
drawSrg->SetConstant(m_viewportSizeIndex, AZ::Vector2(aznumeric_cast<float>(viewportSize.m_width), aznumeric_cast<float>(viewportSize.m_height)));
|
||||
drawSrg->SetImageView(m_textureParameterIndex, image->GetImageView());
|
||||
drawSrg->Compile();
|
||||
|
||||
AZ::Vector3 screenPosition;
|
||||
if (drawParameters.m_positionSpace == CoordinateSpace::ScreenSpace)
|
||||
{
|
||||
screenPosition = drawParameters.m_position;
|
||||
}
|
||||
else if (drawParameters.m_positionSpace == CoordinateSpace::WorldSpace)
|
||||
{
|
||||
using ViewportRequestBus = AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus;
|
||||
AzFramework::ScreenPoint position;
|
||||
ViewportRequestBus::EventResult(position, drawParameters.m_viewport, &ViewportRequestBus::Events::ViewportWorldToScreen, drawParameters.m_position);
|
||||
screenPosition.SetX(aznumeric_cast<float>(position.m_x));
|
||||
screenPosition.SetY(aznumeric_cast<float>(position.m_y));
|
||||
}
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float m_position[3];
|
||||
AZ::u32 m_color;
|
||||
float m_uv[2];
|
||||
};
|
||||
using Indice = AZ::u16;
|
||||
|
||||
// Create a vertex offset from the position to draw from based on the icon size
|
||||
// Vertex positions are in screen space coordinates
|
||||
auto createVertex = [&](float offsetX, float offsetY, float u, float v) -> Vertex
|
||||
{
|
||||
Vertex vertex;
|
||||
screenPosition.StoreToFloat3(vertex.m_position);
|
||||
vertex.m_position[0] += offsetX * drawParameters.m_size.GetX();
|
||||
vertex.m_position[1] += offsetY * drawParameters.m_size.GetY();
|
||||
vertex.m_color = drawParameters.m_color.ToU32();
|
||||
vertex.m_uv[0] = u;
|
||||
vertex.m_uv[1] = v;
|
||||
return vertex;
|
||||
};
|
||||
|
||||
AZStd::array<Vertex, 4> vertices = {
|
||||
createVertex(-0.5f, -0.5f, 0.f, 0.f),
|
||||
createVertex(0.5f, -0.5f, 1.f, 0.f),
|
||||
createVertex(0.5f, 0.5f, 1.f, 1.f),
|
||||
createVertex(-0.5f, 0.5f, 0.f, 1.f)
|
||||
};
|
||||
AZStd::array<Indice, 6> indices = {0, 1, 2, 0, 2, 3};
|
||||
dynamicDraw->DrawIndexed(&vertices, vertices.size(), &indices, indices.size(), RHI::IndexFormat::Uint16, drawSrg);
|
||||
}
|
||||
|
||||
QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& sourceRelativePath) const
|
||||
{
|
||||
bool found = false;
|
||||
AZStd::vector<AZStd::string> scanFolders;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
found, &AzToolsFramework::AssetSystemRequestBus::Events::GetScanFolders, scanFolders);
|
||||
if (!found)
|
||||
{
|
||||
AZ_Error("AtomViewportDisplayIconSystemComponent", false, "Failed to load asset scan folders");
|
||||
return QString();
|
||||
}
|
||||
|
||||
for (const auto& folder : scanFolders)
|
||||
{
|
||||
QDir dir(folder.data());
|
||||
if (dir.exists(sourceRelativePath))
|
||||
{
|
||||
return dir.absoluteFilePath(sourceRelativePath);
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QImage AtomViewportDisplayIconsSystemComponent::RenderSvgToImage(const QString& svgPath) const
|
||||
{
|
||||
// Set up our SVG renderer
|
||||
QSvgRenderer renderer(svgPath);
|
||||
renderer.setAspectRatioMode(Qt::KeepAspectRatio);
|
||||
|
||||
// Set up our target image
|
||||
QSize size = renderer.defaultSize().expandedTo(MinimumRenderedSvgSize);
|
||||
QImage image(size, QtImageFormat);
|
||||
image.fill(0x00000000);
|
||||
|
||||
// Render the SVG
|
||||
QPainter painter(&image);
|
||||
renderer.render(&painter);
|
||||
return image;
|
||||
}
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::Image> AtomViewportDisplayIconsSystemComponent::ConvertToAtomImage(AZ::Uuid assetId, QImage image) const
|
||||
{
|
||||
// Ensure our image is in the correct pixel format so we can memcpy it to our renderer image
|
||||
image.convertTo(QtImageFormat);
|
||||
Data::Instance<RPI::StreamingImagePool> streamingImagePool = RPI::ImageSystemInterface::Get()->GetSystemStreamingPool();
|
||||
return RPI::StreamingImage::CreateFromCpuData(
|
||||
*streamingImagePool.get(),
|
||||
RHI::ImageDimension::Image2D,
|
||||
RHI::Size(image.width(), image.height(), 1),
|
||||
RHI::Format::R8G8B8A8_UNORM_SRGB,
|
||||
image.bits(),
|
||||
image.sizeInBytes(),
|
||||
assetId);
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorViewportIconDisplayInterface::IconId AtomViewportDisplayIconsSystemComponent::GetOrLoadIconForPath(
|
||||
AZStd::string_view path)
|
||||
{
|
||||
AZ_Error(
|
||||
"AtomViewportDisplayIconsSystemComponent", AzFramework::StringFunc::Path::IsRelative(path.data()),
|
||||
"GetOrLoadIconForPath assumes that it will always be given a relative path, but got '%s'", path.data());
|
||||
|
||||
// Check our cache to see if the image is already loaded
|
||||
auto existingEntryIt = AZStd::find_if(m_iconData.begin(), m_iconData.end(), [&path](const auto& iconData)
|
||||
{
|
||||
return iconData.second.m_path == path;
|
||||
});
|
||||
if (existingEntryIt != m_iconData.end())
|
||||
{
|
||||
return existingEntryIt->first;
|
||||
}
|
||||
|
||||
AZ::Uuid assetId = AZ::Uuid::CreateName(path.data());
|
||||
|
||||
// Find the asset to load on disk
|
||||
QString assetPath = FindAssetPath(path.data());
|
||||
if (assetPath.isEmpty())
|
||||
{
|
||||
AZ_Error("AtomViewportDisplayIconSystemComponent", false, "Failed to locate icon on disk: \"%s\"", path.data());
|
||||
return InvalidIconId;
|
||||
}
|
||||
|
||||
QImage loadedImage;
|
||||
|
||||
AZStd::string extension;
|
||||
AzFramework::StringFunc::Path::GetExtension(path.data(), extension, false);
|
||||
// For SVGs, we need to actually rasterize to an image
|
||||
if (extension == "svg")
|
||||
{
|
||||
loadedImage = RenderSvgToImage(assetPath);
|
||||
}
|
||||
// For everything else, we can just load it through QImage via its image plugins
|
||||
else
|
||||
{
|
||||
const bool loaded = loadedImage.load(assetPath);
|
||||
if (!loaded)
|
||||
{
|
||||
AZ_Error("AtomViewportDisplayIconSystemComponent", false, "Failed to load icon: \"%s\"", assetPath.toUtf8().constData());
|
||||
return InvalidIconId;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache our loaded icon
|
||||
IconId id = m_currentId++;
|
||||
IconData& iconData = m_iconData[id];
|
||||
iconData.m_path = path;
|
||||
iconData.m_image = ConvertToAtomImage(assetId, loadedImage);
|
||||
return id;
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorViewportIconDisplayInterface::IconLoadStatus AtomViewportDisplayIconsSystemComponent::GetIconLoadStatus(
|
||||
IconId icon)
|
||||
{
|
||||
auto iconIt = m_iconData.find(icon);
|
||||
if (iconIt == m_iconData.end())
|
||||
{
|
||||
return IconLoadStatus::Unloaded;
|
||||
}
|
||||
if (iconIt->second.m_image)
|
||||
{
|
||||
return IconLoadStatus::Loaded;
|
||||
}
|
||||
return IconLoadStatus::Error;
|
||||
}
|
||||
|
||||
void AtomViewportDisplayIconsSystemComponent::OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene)
|
||||
{
|
||||
AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(m_drawContextName, [](RPI::Ptr<RPI::DynamicDrawContext> drawContext)
|
||||
{
|
||||
auto shader = RPI::LoadShader(DrawContextShaderPath);
|
||||
drawContext->InitShader(shader);
|
||||
drawContext->InitVertexFormat(
|
||||
{{"POSITION", RHI::Format::R32G32B32_FLOAT},
|
||||
{"COLOR", RHI::Format::R8G8B8A8_UNORM},
|
||||
{"TEXCOORD", RHI::Format::R32G32_FLOAT}});
|
||||
drawContext->EndInit();
|
||||
});
|
||||
}
|
||||
} // namespace AZ::Render
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
|
||||
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
|
||||
|
||||
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
|
||||
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class TickRequests;
|
||||
|
||||
namespace Render
|
||||
{
|
||||
class AtomViewportDisplayIconsSystemComponent
|
||||
: public AZ::Component
|
||||
, public AzToolsFramework::EditorViewportIconDisplayInterface
|
||||
, public AZ::Render::Bootstrap::NotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AtomViewportDisplayIconsSystemComponent, "{AEC1D3E1-1D9A-437A-B4C6-CFAEE620C160}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
protected:
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// AzToolsFramework::EditorViewportIconDisplayInterface overrides...
|
||||
void DrawIcon(const DrawParameters& drawParameters) override;
|
||||
IconId GetOrLoadIconForPath(AZStd::string_view path) override;
|
||||
IconLoadStatus GetIconLoadStatus(IconId icon) override;
|
||||
|
||||
// AZ::Render::Bootstrap::NotificationBus::Handler overrides...
|
||||
void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override;
|
||||
|
||||
private:
|
||||
static constexpr const char* DrawContextShaderPath = "Shaders/TexturedIcon.azshader";
|
||||
static constexpr QSize MinimumRenderedSvgSize = QSize(128, 128);
|
||||
static constexpr QImage::Format QtImageFormat = QImage::Format_RGBA8888;
|
||||
|
||||
QString FindAssetPath(const QString& sourceRelativePath) const;
|
||||
QImage RenderSvgToImage(const QString& svgPath) const;
|
||||
AZ::Data::Instance<AZ::RPI::Image> ConvertToAtomImage(AZ::Uuid assetId, QImage image) const;
|
||||
|
||||
Name m_drawContextName = Name("ViewportIconDisplay");
|
||||
bool m_shaderIndexesInitialized = false;
|
||||
RHI::ShaderInputNameIndex m_textureParameterIndex = "m_texture";
|
||||
RHI::ShaderInputNameIndex m_viewportSizeIndex = "m_viewportSize";
|
||||
|
||||
struct IconData
|
||||
{
|
||||
AZStd::string m_path;
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_image = nullptr;
|
||||
};
|
||||
AZStd::unordered_map<IconId, IconData> m_iconData;
|
||||
IconId m_currentId = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/Module/Module.h>
|
||||
|
||||
#include "AtomViewportDisplayIconsSystemComponent.h"
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class AtomViewportDisplayInfoModule
|
||||
: public AZ::Module
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AtomViewportDisplayInfoModule, "{8D72F14E-958D-4225-B3BC-C5C87BDDD426}", AZ::Module);
|
||||
AZ_CLASS_ALLOCATOR(AtomViewportDisplayInfoModule, AZ::SystemAllocator, 0);
|
||||
|
||||
AtomViewportDisplayInfoModule()
|
||||
: AZ::Module()
|
||||
{
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
AtomViewportDisplayIconsSystemComponent::CreateDescriptor(),
|
||||
});
|
||||
}
|
||||
|
||||
AZ::ComponentTypeList GetRequiredSystemComponents() const override
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<AtomViewportDisplayIconsSystemComponent>(),
|
||||
};
|
||||
}
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
|
||||
// The first parameter should be GemName_GemIdLower
|
||||
// The second should be the fully qualified name of the class above
|
||||
AZ_DECLARE_MODULE_CLASS(Gem_AtomViewportDisplayInfo, AZ::Render::AtomViewportDisplayInfoModule)
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Source/AtomViewportDisplayIconsSystemComponent.cpp
|
||||
Source/AtomViewportDisplayIconsSystemComponent.h
|
||||
Source/Module.cpp
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"gem_name": "AtomLyIntegration_AtomViewportDisplayInfo",
|
||||
"display_name": "Atom Viewport Display Info Overlay",
|
||||
"summary": "Provides a diagnostic viewport overlay for the default O3DE Atom viewport.",
|
||||
"canonical_tags": [
|
||||
"Gem"
|
||||
],
|
||||
"user_tags": [
|
||||
"AtomLyIntegration",
|
||||
"AtomViewportDisplayInfo"
|
||||
]
|
||||
}
|
||||
@@ -17,3 +17,4 @@ add_subdirectory(AtomFont)
|
||||
add_subdirectory(TechnicalArt)
|
||||
add_subdirectory(AtomBridge)
|
||||
add_subdirectory(AtomViewportDisplayInfo)
|
||||
add_subdirectory(AtomViewportDisplayIcons)
|
||||
|
||||
Reference in New Issue
Block a user