123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762 |
- /*
- * 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 "LyShine.h"
- #include "UiCanvasComponent.h"
- #include "UiCanvasManager.h"
- #include "LyShineDebug.h"
- #include "UiElementComponent.h"
- #include "UiTransform2dComponent.h"
- #include "UiImageComponent.h"
- #include "UiTextComponent.h"
- #include "UiButtonComponent.h"
- #include "UiCheckboxComponent.h"
- #include "UiSliderComponent.h"
- #include "UiTextInputComponent.h"
- #include "UiScrollBarComponent.h"
- #include "UiScrollBoxComponent.h"
- #include "UiFaderComponent.h"
- #include "UiFlipbookAnimationComponent.h"
- #include "UiLayoutFitterComponent.h"
- #include "UiMarkupButtonComponent.h"
- #include "UiMaskComponent.h"
- #include "UiLayoutColumnComponent.h"
- #include "UiLayoutRowComponent.h"
- #include "UiLayoutGridComponent.h"
- #include "UiParticleEmitterComponent.h"
- #include "UiRadioButtonComponent.h"
- #include "UiRadioButtonGroupComponent.h"
- #include "UiTooltipComponent.h"
- #include "UiTooltipDisplayComponent.h"
- #include "UiDynamicLayoutComponent.h"
- #include "UiDynamicScrollBoxComponent.h"
- #include "UiDropdownComponent.h"
- #include "UiDropdownOptionComponent.h"
- #include "Script/UiCanvasNotificationLuaBus.h"
- #include "Script/UiCanvasLuaBus.h"
- #include "Script/UiElementLuaBus.h"
- #include "Sprite.h"
- #include "UiSerialize.h"
- #include "UiRenderer.h"
- #include "Draw2d.h"
- #include <LyShine/Bus/UiCursorBus.h>
- #include <LyShine/Bus/UiDraggableBus.h>
- #include <LyShine/Bus/UiDropTargetBus.h>
- #if defined(LYSHINE_INTERNAL_UNIT_TEST)
- #include "TextMarkup.h"
- #endif
- #include <AzCore/Math/Crc.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <AzCore/Script/ScriptContextAttributes.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzCore/Memory/PoolAllocator.h>
- #include <AzCore/Asset/AssetTypeInfoBus.h>
- #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
- #include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
- #include <AzFramework/Metrics/MetricsPlainTextNameRegistration.h>
- #include <Atom/RHI/RHIUtils.h>
- #include "Animation/UiAnimationSystem.h"
- #include "World/UiCanvasAssetRefComponent.h"
- #include "World/UiCanvasProxyRefComponent.h"
- #include "World/UiCanvasOnMeshComponent.h"
- //! \brief Simple utility class for LyShine functionality in Lua.
- //!
- //! Functionality unrelated to UI, such as showing the mouse cursor, should
- //! eventually be moved into other modules (for example, mouse cursor functionality
- //! should be moved to input, which matches more closely how FG modules are
- //! organized).
- class LyShineLua
- {
- public:
- static void ShowMouseCursor(bool visible)
- {
- static bool sShowCursor = false;
- if (visible)
- {
- if (!sShowCursor)
- {
- sShowCursor = true;
- UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter);
- }
- }
- else
- {
- if (sShowCursor)
- {
- sShowCursor = false;
- UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter);
- }
- }
- }
- };
- namespace AZ
- {
- AZ_TYPE_INFO_SPECIALIZE(LyShineLua, "{2570D3B3-2D18-4DB1-A0DE-E017A2F491D1}");
- }
- // This is the memory allocation for the static data member used for the debug console variables
- #ifndef _RELEASE
- AllocateConstIntCVar(CLyShine, CV_ui_DisplayTextureData);
- AllocateConstIntCVar(CLyShine, CV_ui_DisplayCanvasData);
- AllocateConstIntCVar(CLyShine, CV_ui_DisplayDrawCallData);
- AllocateConstIntCVar(CLyShine, CV_ui_DisplayElemBounds);
- AllocateConstIntCVar(CLyShine, CV_ui_DisplayElemBoundsCanvasIndex);
- #endif
- #if defined(LYSHINE_INTERNAL_UNIT_TEST)
- AllocateConstIntCVar(CLyShine, CV_ui_RunUnitTestsOnStartup);
- #endif
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- CLyShine::CLyShine()
- : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityUI())
- , AzFramework::InputTextEventListener(AzFramework::InputTextEventListener::GetPriorityUI())
- , m_draw2d(new CDraw2d)
- , m_uiRenderer(new UiRenderer)
- , m_uiCanvasManager(new UiCanvasManager)
- , m_uiCursorVisibleCounter(0)
- {
- // Reflect the Deprecated Lua buses using the behavior context.
- // This support will be removed at some point
- {
- AZ::BehaviorContext* behaviorContext = nullptr;
- AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationBus::Events::GetBehaviorContext);
- if (behaviorContext)
- {
- behaviorContext->Class<LyShineLua>("LyShineLua")
- ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
- ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
- ->Method("ShowMouseCursor", &LyShineLua::ShowMouseCursor)
- ;
- UiCanvasNotificationLuaProxy::Reflect(behaviorContext);
- UiCanvasLuaProxy::Reflect(behaviorContext);
- UiElementLuaProxy::Reflect(behaviorContext);
- }
- }
- CSprite::Initialize();
- LyShineDebug::Initialize();
- UiElementComponent::Initialize();
- UiCanvasComponent::Initialize();
- AzFramework::InputChannelEventListener::Connect();
- AzFramework::InputTextEventListener::Connect();
- UiCursorBus::Handler::BusConnect();
- AZ::TickBus::Handler::BusConnect();
- AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(
- AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName());
- 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
- // This is internal Amazon code, so register it's components for metrics tracking, otherwise the name of the component won't get sent back.
- AZStd::vector<AZ::Uuid> componentUuidsForMetricsCollection
- {
- azrtti_typeid<UiCanvasAssetRefComponent>(),
- azrtti_typeid<UiCanvasProxyRefComponent>(),
- azrtti_typeid<UiCanvasOnMeshComponent>(),
- azrtti_typeid<UiCanvasComponent>(),
- azrtti_typeid<UiElementComponent>(),
- azrtti_typeid<UiTransform2dComponent>(),
- azrtti_typeid<UiImageComponent>(),
- azrtti_typeid<UiTextComponent>(),
- azrtti_typeid<UiButtonComponent>(),
- azrtti_typeid<UiCheckboxComponent>(),
- azrtti_typeid<UiSliderComponent>(),
- azrtti_typeid<UiTextInputComponent>(),
- azrtti_typeid<UiScrollBarComponent>(),
- azrtti_typeid<UiScrollBoxComponent>(),
- azrtti_typeid<UiFaderComponent>(),
- azrtti_typeid<UiFlipbookAnimationComponent>(),
- azrtti_typeid<UiMarkupButtonComponent>(),
- azrtti_typeid<UiMaskComponent>(),
- azrtti_typeid<UiLayoutColumnComponent>(),
- azrtti_typeid<UiLayoutRowComponent>(),
- azrtti_typeid<UiLayoutGridComponent>(),
- azrtti_typeid<UiRadioButtonComponent>(),
- azrtti_typeid<UiRadioButtonGroupComponent>(),
- azrtti_typeid<UiDropdownComponent>(),
- azrtti_typeid<UiDropdownOptionComponent>(),
- azrtti_typeid<UiLayoutFitterComponent>(),
- azrtti_typeid<UiParticleEmitterComponent>(),
- };
- AzFramework::MetricsPlainTextNameRegistrationBus::Broadcast(
- &AzFramework::MetricsPlainTextNameRegistrationBus::Events::RegisterForNameSending, componentUuidsForMetricsCollection);
- #ifndef _RELEASE
- // Define a debug console variable that controls display of some debug info on UI texture usage
- DefineConstIntCVar3("ui_DisplayTextureData", CV_ui_DisplayTextureData, 0, VF_CHEAT,
- "0=off, 1=display info for all textures used in the frame");
- // Define a debug console variable that controls display of some debug info for all canvases
- DefineConstIntCVar3("ui_DisplayCanvasData", CV_ui_DisplayCanvasData, 0, VF_CHEAT,
- "0=off, 1=display info for all loaded UI canvases, 2=display info for all enabled UI canvases");
- // Define a debug console variable that controls display of some debug info on UI draw calls
- DefineConstIntCVar3("ui_DisplayDrawCallData", CV_ui_DisplayDrawCallData, 0, VF_CHEAT,
- "0=off, 1=display draw call info for all loaded and enabled UI canvases");
-
- // Define a debug console variable that controls display of all element bounds when in game
- DefineConstIntCVar3("ui_DisplayElemBounds", CV_ui_DisplayElemBounds, 0, VF_CHEAT,
- "0=off, 1=display the UI element bounding boxes");
- // Define a debug console variable that filters the display of all element bounds when in game by canvas index
- DefineConstIntCVar3("ui_DisplayElemBoundsCanvasIndex", CV_ui_DisplayElemBoundsCanvasIndex, -1, VF_CHEAT,
- "-1=no filter, 0-N=only for elements from this canvas index (see 'ui_displayCanvasData 2' for index)");
- // Define a console command that outputs a report to a file about the draw calls for all enabled canvases
- REGISTER_COMMAND("ui_ReportDrawCalls", &DebugReportDrawCalls, VF_NULL, "");
- #endif
- #if defined(LYSHINE_INTERNAL_UNIT_TEST)
- DefineConstIntCVar3("ui_RunUnitTestsOnStartup", CV_ui_RunUnitTestsOnStartup, 0, VF_CHEAT,
- "0=off, 1=run LyShine unit tests on startup");
- REGISTER_COMMAND("ui_RunUnitTests", &RunUnitTests, VF_NULL, "");
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- CLyShine::~CLyShine()
- {
- UiCursorBus::Handler::BusDisconnect();
- AZ::TickBus::Handler::BusDisconnect();
- AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
- AzFramework::InputTextEventListener::Disconnect();
- AzFramework::InputChannelEventListener::Disconnect();
- AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
- LyShinePassDataRequestBus::Handler::BusDisconnect();
- UiCanvasComponent::Shutdown();
- // must be done after UiCanvasComponent::Shutdown
- CSprite::Shutdown();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::Release()
- {
- delete this;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- IDraw2d* CLyShine::GetDraw2d()
- {
- return m_draw2d.get();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- UiRenderer* CLyShine::GetUiRenderer()
- {
- return m_uiRenderer.get();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- UiRenderer* CLyShine::GetUiRendererForEditor()
- {
- return m_uiRendererForEditor.get();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::SetUiRendererForEditor(AZStd::shared_ptr<UiRenderer> uiRenderer)
- {
- m_uiRendererForEditor = uiRenderer;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::CreateCanvas()
- {
- return m_uiCanvasManager->CreateCanvas();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::LoadCanvas(const AZStd::string& assetIdPathname)
- {
- return m_uiCanvasManager->LoadCanvas(assetIdPathname.c_str());
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::CreateCanvasInEditor(UiEntityContext* entityContext)
- {
- return m_uiCanvasManager->CreateCanvasInEditor(entityContext);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::LoadCanvasInEditor(const AZStd::string& assetIdPathname, const AZStd::string& sourceAssetPathname, UiEntityContext* entityContext)
- {
- return m_uiCanvasManager->LoadCanvasInEditor(assetIdPathname, sourceAssetPathname, entityContext);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::ReloadCanvasFromXml(const AZStd::string& xmlString, UiEntityContext* entityContext)
- {
- return m_uiCanvasManager->ReloadCanvasFromXml(xmlString, entityContext);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::FindCanvasById(LyShine::CanvasId id)
- {
- return m_uiCanvasManager->FindCanvasById(id);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::EntityId CLyShine::FindLoadedCanvasByPathName(const AZStd::string& assetIdPathname)
- {
- return m_uiCanvasManager->FindLoadedCanvasByPathName(assetIdPathname.c_str());
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::ReleaseCanvas(AZ::EntityId canvas, bool forEditor)
- {
- m_uiCanvasManager->ReleaseCanvas(canvas, forEditor);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::ReleaseCanvasDeferred(AZ::EntityId canvas)
- {
- m_uiCanvasManager->ReleaseCanvasDeferred(canvas);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- ISprite* CLyShine::LoadSprite(const AZStd::string& pathname)
- {
- return CSprite::LoadSprite(pathname);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- ISprite* CLyShine::CreateSprite(const AZ::Data::Asset<AZ::RPI::AttachmentImageAsset>& attachmentImageAsset)
- {
- return CSprite::CreateSprite(attachmentImageAsset);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool CLyShine::DoesSpriteTextureAssetExist(const AZStd::string& pathname)
- {
- return CSprite::DoesSpriteTextureAssetExist(pathname);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::Data::Instance<AZ::RPI::Image> CLyShine::LoadTexture(const AZStd::string& pathname)
- {
- return CDraw2d::LoadTexture(pathname);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::PostInit()
- {
- #if defined(LYSHINE_INTERNAL_UNIT_TEST)
- if (CV_ui_RunUnitTestsOnStartup)
- {
- RunUnitTests(nullptr);
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::SetViewportSize(AZ::Vector2 viewportSize)
- {
- // Pass the viewport size to UiCanvasComponents
- m_uiCanvasManager->SetTargetSizeForLoadedCanvases(viewportSize);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::Update(float deltaTimeInSeconds)
- {
- if (!m_uiRenderer->IsReady())
- {
- return;
- }
- // Tell the UI system the size of the viewport we are rendering to - this drives the
- // canvas size for full screen UI canvases. It needs to be set before either lyShine->Update or
- // lyShine->Render are called. It must match the viewport size that the input system is using.
- SetViewportSize(m_uiRenderer->GetViewportSize());
- // Guard against nested updates. This can occur if a canvas update below triggers the load screen component's
- // UpdateAndRender (ex. when a texture is loaded)
- if (!m_updatingLoadedCanvases)
- {
- m_updatingLoadedCanvases = true;
- // Update all the canvases loaded in game
- m_uiCanvasManager->UpdateLoadedCanvases(deltaTimeInSeconds);
- // Execute events that have been queued during the canvas update
- ExecuteQueuedEvents();
- m_updatingLoadedCanvases = false;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::Render()
- {
- if (AZ::RHI::IsNullRHI())
- {
- return;
- }
- if (m_updatingLoadedCanvases)
- {
- // Don't render if an update is in progress. This can occur if an update triggers the
- // load screen component's UpdateAndRender (ex. when a texture is loaded)
- return;
- }
- if (!m_uiRenderer->IsReady())
- {
- return;
- }
- #ifndef _RELEASE
- GetUiRenderer()->DebugSetRecordingOptionForTextureData(CV_ui_DisplayTextureData);
- #endif
-
- GetUiRenderer()->BeginUiFrameRender();
-
- // 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
- // cursor. But it would draw in the wrong place. It is better to just rely on the regular editor cursor in preview
- // since, in game, the game cursor could be turned on and off any any point, so each UI canvas is not necessarily
- // going to turn it on.
- if (!(gEnv->IsEditor() && gEnv->IsEditing()))
- {
- RenderUiCursor();
- }
- GetUiRenderer()->EndUiFrameRender();
- #ifndef _RELEASE
- if (CV_ui_DisplayElemBounds)
- {
- m_uiCanvasManager->DebugDisplayElemBounds(CV_ui_DisplayElemBoundsCanvasIndex);
- }
- if (CV_ui_DisplayTextureData)
- {
- GetUiRenderer()->DebugDisplayTextureData(CV_ui_DisplayTextureData);
- }
- else if (CV_ui_DisplayCanvasData)
- {
- m_uiCanvasManager->DebugDisplayCanvasData(CV_ui_DisplayCanvasData);
- }
- else if (CV_ui_DisplayDrawCallData)
- {
- m_uiCanvasManager->DebugDisplayDrawCallData();
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::ExecuteQueuedEvents()
- {
- // Execute events that have been queued during the canvas update
- UiFaderNotificationBus::ExecuteQueuedEvents();
- UiAnimationNotificationBus::ExecuteQueuedEvents();
- // Execute events that have been queued during the input event handler
- UiDraggableNotificationBus::ExecuteQueuedEvents(); // draggable must be done before drop target
- UiDropTargetNotificationBus::ExecuteQueuedEvents();
- UiCanvasNotificationBus::ExecuteQueuedEvents();
- UiButtonNotificationBus::ExecuteQueuedEvents();
- UiInteractableNotificationBus::ExecuteQueuedEvents();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::Reset()
- {
- // This is called when the game is terminated.
- // Reset the debug module - this should be called before DestroyLoadedCanvases since it
- // tracks the loaded debug canvas
- LyShineDebug::Reset();
- // Delete all the canvases in m_canvases map that are not open in the editor.
- m_uiCanvasManager->DestroyLoadedCanvases(false);
- // Ensure that the UI Cursor is hidden.
- LyShineLua::ShowMouseCursor(false);
- m_uiCursorVisibleCounter = 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::OnLevelUnload()
- {
- // This is called when a level is unloaded or a new level is initialized
- // Reset the debug module - this should be called before DestroyLoadedCanvases since it
- // tracks the loaded debug canvas
- LyShineDebug::Reset();
- // Delete all the canvases in m_canvases map that a not loaded in the editor and are not
- // marked to be kept between levels.
- m_uiCanvasManager->DestroyLoadedCanvases(true);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::OnLoadScreenUnloaded()
- {
- m_uiCanvasManager->OnLoadScreenUnloaded();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::IncrementVisibleCounter()
- {
- ++m_uiCursorVisibleCounter;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::DecrementVisibleCounter()
- {
- --m_uiCursorVisibleCounter;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool CLyShine::IsUiCursorVisible()
- {
- return m_uiCursorVisibleCounter > 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::SetUiCursor(const char* cursorImagePath)
- {
- m_uiCursorTexture.reset();
- m_cursorImagePathToLoad.clear();
- if (cursorImagePath && *cursorImagePath)
- {
- 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())
- {
- LoadUiCursor();
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- AZ::Vector2 CLyShine::GetUiCursorPosition()
- {
- AZ::Vector2 systemCursorPositionNormalized;
- AzFramework::InputSystemCursorRequestBus::EventResult(systemCursorPositionNormalized,
- AzFramework::InputDeviceMouse::Id,
- &AzFramework::InputSystemCursorRequests::GetSystemCursorPositionNormalized);
- AZ::Vector2 viewportSize = m_uiRenderer->GetViewportSize();
- return AZ::Vector2(systemCursorPositionNormalized.GetX() * viewportSize.GetX(),
- systemCursorPositionNormalized.GetY() * viewportSize.GetY());
- }
- void CLyShine::SetUiCursorPosition(const AZ::Vector2& positionNormalized)
- {
- AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::SetSystemCursorPositionNormalized, positionNormalized);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool CLyShine::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
- {
- // disable UI inputs when console is open except for a primary release
- // if we ignore the primary release when there is an active interactable then it will miss its release
- // which leaves it in a bad state. E.g. a drag operation will be left in flight and not properly
- // terminated.
- if (gEnv->pConsole->GetStatus())
- {
- bool isPrimaryRelease = false;
- if (inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Button::Left ||
- inputChannel.GetInputChannelId() == AzFramework::InputDeviceTouch::Touch::Index0)
- {
- if (inputChannel.IsStateEnded())
- {
- isPrimaryRelease = true;
- }
- }
- if (!isPrimaryRelease)
- {
- return false;
- }
- }
- bool result = m_uiCanvasManager->HandleInputEventForLoadedCanvases(inputChannel);
- if (result)
- {
- // Execute events that have been queued during the input event handler
- ExecuteQueuedEvents();
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool CLyShine::OnInputTextEventFiltered(const AZStd::string& textUTF8)
- {
- if (gEnv->pConsole->GetStatus()) // disable UI inputs when console is open
- {
- return false;
- }
- bool result = m_uiCanvasManager->HandleTextEventForLoadedCanvases(textUTF8);
- if (result)
- {
- // Execute events that have been queued during the input event handler
- ExecuteQueuedEvents();
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
- {
- // Update the loaded UI canvases
- Update(deltaTime);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- int CLyShine::GetTickOrder()
- {
- return AZ::TICK_PRE_RENDER;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::OnRenderTick()
- {
- // Recreate dirty render graphs and send primitive data to the dynamic draw context
- Render();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
- {
- // Load cursor if its path was set before RPI was initialized
- LoadUiCursor();
- LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId());
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- LyShine::AttachmentImagesAndDependencies CLyShine::GetRenderTargets()
- {
- LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies;
- m_uiCanvasManager->GetRenderTargets(attachmentImagesAndDependencies);
- return attachmentImagesAndDependencies;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::LoadUiCursor()
- {
- if (!m_cursorImagePathToLoad.empty())
- {
- m_uiCursorTexture = CDraw2d::LoadTexture(m_cursorImagePathToLoad);
- m_cursorImagePathToLoad.clear();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::RenderUiCursor()
- {
- if (!m_uiCursorTexture || !IsUiCursorVisible())
- {
- return;
- }
- const AzFramework::InputDevice* mouseDevice = AzFramework::InputDeviceRequests::FindInputDevice(AzFramework::InputDeviceMouse::Id);
- if (!mouseDevice || !mouseDevice->IsConnected())
- {
- return;
- }
- const AZ::Vector2 position = GetUiCursorPosition();
- AZ::RHI::Size cursorSize = m_uiCursorTexture->GetDescriptor().m_size;
- const AZ::Vector2 dimensions(aznumeric_cast<float>(cursorSize.m_width), aznumeric_cast<float>(cursorSize.m_height));
- IDraw2d::ImageOptions imageOptions;
- imageOptions.m_clamp = true;
- const float opacity = 1.0f;
- const float rotation = 0.0f;
- const AZ::Vector2* pivotPoint = nullptr;
- const AZ::Vector2* minMaxTexCoords = nullptr;
- m_draw2d->DrawImage(m_uiCursorTexture, position, dimensions, opacity, rotation, pivotPoint, minMaxTexCoords, &imageOptions);
- }
- #ifndef _RELEASE
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::DebugReportDrawCalls(IConsoleCmdArgs* cmdArgs)
- {
- if (AZ::Interface<ILyShine>::Get())
- {
- // We want to use an internal-only non-static function so downcast to CLyShine
- CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
- // There is an optional parameter which is a name to include in the output filename
- AZStd::string name;
- if (cmdArgs->GetArgCount() > 1)
- {
- name = cmdArgs->GetArg(1);
- }
- // Use the canvas manager to access all the loaded canvases
- lyShine->m_uiCanvasManager->DebugReportDrawCalls(name);
- }
- }
- #endif
- #if defined(LYSHINE_INTERNAL_UNIT_TEST)
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void CLyShine::RunUnitTests(IConsoleCmdArgs* cmdArgs)
- {
- // Tests are only valid from the launcher or from game mode (within the editor)
- const bool inEditorEnvironment = gEnv && gEnv->IsEditor() && gEnv->IsEditing();
- if (inEditorEnvironment)
- {
- AZ_Warning("LyShine", false,
- "Unit-tests: skipping! Editor environment detected. Run tests "
- "within editor via game mode (using ui_RunUnitTests) or use "
- "the standalone launcher instead.");
-
- return;
- }
- CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
- AZ_Assert(lyShine, "Attempting to run unit-tests prior to LyShine initialization!");
- TextMarkup::UnitTest(cmdArgs);
- UiTextComponent::UnitTest(lyShine, cmdArgs);
- UiTextComponent::UnitTestLocalization(lyShine, cmdArgs);
- UiTransform2dComponent::UnitTest(lyShine, cmdArgs);
- UiMarkupButtonComponent::UnitTest(lyShine, cmdArgs);
- }
- #endif
|