From 3219c787ac66bf19dea7040581a27e2a80fa2d77 Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Thu, 6 May 2021 13:27:46 -0700 Subject: [PATCH] UI cursor Atom conversion (#607) --- Gems/LyShine/Code/CMakeLists.txt | 1 + Gems/LyShine/Code/Source/LyShine.cpp | 69 ++++++++++++++++++---------- Gems/LyShine/Code/Source/LyShine.h | 12 ++++- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 9c46a61236..732bd1cfd4 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -93,6 +93,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC Gem::Atom_RPI.Public Gem::Atom_Utils.Static + Gem::Atom_Bootstrap.Headers ) ly_add_target( diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index bc6a27dac4..679cae3421 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -137,7 +137,6 @@ CLyShine::CLyShine(ISystem* system) , m_draw2d(new CDraw2d) , m_uiRenderer(new UiRenderer) , m_uiCanvasManager(new UiCanvasManager) - , m_uiCursorTexture(nullptr) , m_uiCursorVisibleCounter(0) { // Reflect the Deprecated Lua buses using the behavior context. @@ -170,6 +169,7 @@ CLyShine::CLyShine(ISystem* system) AzFramework::InputTextEventListener::Connect(); UiCursorBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); + AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); // These are internal Amazon components, so register them so that we can send back their names to our metrics collection // IF YOU ARE A THIRDPARTY WRITING A GEM, DO NOT REGISTER YOUR COMPONENTS WITH EditorMetricsComponentRegistrationBus @@ -248,17 +248,12 @@ CLyShine::~CLyShine() AZ::TickBus::Handler::BusDisconnect(); AzFramework::InputTextEventListener::Disconnect(); AzFramework::InputChannelEventListener::Disconnect(); + AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect(); UiCanvasComponent::Shutdown(); // must be done after UiCanvasComponent::Shutdown CSprite::Shutdown(); - - if (m_uiCursorTexture) - { - m_uiCursorTexture->Release(); - m_uiCursorTexture = nullptr; - } } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -443,6 +438,9 @@ void CLyShine::Render() // Render all the canvases loaded in game m_uiCanvasManager->RenderLoadedCanvases(); + // Set sort key for draw2d layer to ensure it renders in front of the canvases + static const int64_t topLayerKey = 0x1000000; + m_draw2d->SetSortKey(topLayerKey); m_draw2d->RenderDeferredPrimitives(); // Don't render the UI cursor when in edit mode. For example during UI Preview mode a script could turn on the @@ -558,18 +556,20 @@ bool CLyShine::IsUiCursorVisible() //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::SetUiCursor(const char* cursorImagePath) { - if (m_uiCursorTexture) - { - m_uiCursorTexture->Release(); - m_uiCursorTexture = nullptr; - } + m_uiCursorTexture.reset(); + m_cursorImagePathToLoad.clear(); - if (cursorImagePath && *cursorImagePath && gEnv && gEnv->pRenderer) + if (cursorImagePath && *cursorImagePath) { - m_uiCursorTexture = gEnv->pRenderer->EF_LoadTexture(cursorImagePath, FT_DONT_RELEASE | FT_DONT_STREAM); - if (m_uiCursorTexture) + m_cursorImagePathToLoad = cursorImagePath; + // The cursor image can only be loaded after the RPI has been initialized. + // Note: this check could be avoided if LyShineSystemComponent included the RPISystem + // as a required service. However, LyShineSystempComponent is currently activated for + // tools as well as game and RPIService is not available with all tools such as AP. An + // enhancement would be to break LyShineSystemComponent into a game only component + if (m_uiRenderer->IsReady()) { - m_uiCursorTexture->SetClamp(true); + LoadUiCursor(); } } } @@ -581,8 +581,11 @@ AZ::Vector2 CLyShine::GetUiCursorPosition() AzFramework::InputSystemCursorRequestBus::EventResult(systemCursorPositionNormalized, AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::GetSystemCursorPositionNormalized); - return AZ::Vector2(systemCursorPositionNormalized.GetX() * static_cast(gEnv->pRenderer->GetOverlayWidth()), - systemCursorPositionNormalized.GetY() * static_cast(gEnv->pRenderer->GetOverlayHeight())); + + AZ::Vector2 viewportSize = m_uiRenderer->GetViewportSize(); + + return AZ::Vector2(systemCursorPositionNormalized.GetX() * viewportSize.GetX(), + systemCursorPositionNormalized.GetY() * viewportSize.GetY()); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -642,6 +645,7 @@ bool CLyShine::OnInputTextEventFiltered(const AZStd::string& textUTF8) return result; } +//////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { // Update the loaded UI canvases @@ -651,15 +655,33 @@ void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time Render(); } +//////////////////////////////////////////////////////////////////////////////////////////////////// int CLyShine::GetTickOrder() { return AZ::TICK_UI; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +{ + // Load cursor if its path was set before RPI was initialized + LoadUiCursor(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CLyShine::LoadUiCursor() +{ + if (!m_cursorImagePathToLoad.empty()) + { + m_uiCursorTexture = CDraw2d::LoadTexture(m_cursorImagePathToLoad); // LYSHINE_ATOM_TODO - add clamp option to draw2d and set cursor to clamp + m_cursorImagePathToLoad.clear(); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::RenderUiCursor() { - if (!gEnv || !gEnv->pRenderer || !m_uiCursorTexture || !IsUiCursorVisible()) + if (!m_uiCursorTexture || !IsUiCursorVisible()) { return; } @@ -671,13 +693,10 @@ void CLyShine::RenderUiCursor() } const AZ::Vector2 position = GetUiCursorPosition(); - const AZ::Vector2 dimensions(static_cast(m_uiCursorTexture->GetWidth()), static_cast(m_uiCursorTexture->GetHeight())); + AZ::RHI::Size cursorSize = m_uiCursorTexture->GetDescriptor().m_size; + const AZ::Vector2 dimensions(aznumeric_cast(cursorSize.m_width), aznumeric_cast(cursorSize.m_height)); -#ifdef LYSHINE_ATOM_TODO // Convert cursor to Atom image - m_draw2d->BeginDraw2d(); - m_draw2d->DrawImage(m_uiCursorTexture->GetTextureID(), position, dimensions); - m_draw2d->EndDraw2d(); -#endif + m_draw2d->DrawImage(m_uiCursorTexture, position, dimensions); } #ifndef _RELEASE diff --git a/Gems/LyShine/Code/Source/LyShine.h b/Gems/LyShine/Code/Source/LyShine.h index 943f5fa537..4c46b0db19 100644 --- a/Gems/LyShine/Code/Source/LyShine.h +++ b/Gems/LyShine/Code/Source/LyShine.h @@ -19,6 +19,9 @@ #include #include +#include +#include + #if !defined(_RELEASE) #define LYSHINE_INTERNAL_UNIT_TEST #endif @@ -41,6 +44,7 @@ class CLyShine , public AzFramework::InputChannelEventListener , public AzFramework::InputTextEventListener , public AZ::TickBus::Handler + , protected AZ::Render::Bootstrap::NotificationBus::Handler { public: @@ -111,6 +115,10 @@ public: int GetTickOrder() override; // ~TickEvents + // AZ::Render::Bootstrap::NotificationBus + void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override; + // ~AZ::Render::Bootstrap::NotificationBus + // Get the UIRenderer for the game (which is owned by CLyShine). This is not exposed outside the gem. UiRenderer* GetUiRenderer(); @@ -128,6 +136,7 @@ private: // member functions AZ_DISABLE_COPY_MOVE(CLyShine); + void LoadUiCursor(); void RenderUiCursor(); private: // static member functions @@ -146,7 +155,8 @@ private: // data std::unique_ptr m_uiCanvasManager; - ITexture* m_uiCursorTexture; + AZStd::string m_cursorImagePathToLoad; + AZ::Data::Instance m_uiCursorTexture; int m_uiCursorVisibleCounter; bool m_updatingLoadedCanvases = false; // guard against nested updates