LyShine.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "LyShine.h"
  9. #include "UiCanvasComponent.h"
  10. #include "UiCanvasManager.h"
  11. #include "LyShineDebug.h"
  12. #include "UiElementComponent.h"
  13. #include "UiTransform2dComponent.h"
  14. #include "UiImageComponent.h"
  15. #include "UiTextComponent.h"
  16. #include "UiButtonComponent.h"
  17. #include "UiCheckboxComponent.h"
  18. #include "UiSliderComponent.h"
  19. #include "UiTextInputComponent.h"
  20. #include "UiScrollBarComponent.h"
  21. #include "UiScrollBoxComponent.h"
  22. #include "UiFaderComponent.h"
  23. #include "UiFlipbookAnimationComponent.h"
  24. #include "UiLayoutFitterComponent.h"
  25. #include "UiMarkupButtonComponent.h"
  26. #include "UiMaskComponent.h"
  27. #include "UiLayoutColumnComponent.h"
  28. #include "UiLayoutRowComponent.h"
  29. #include "UiLayoutGridComponent.h"
  30. #include "UiParticleEmitterComponent.h"
  31. #include "UiRadioButtonComponent.h"
  32. #include "UiRadioButtonGroupComponent.h"
  33. #include "UiTooltipComponent.h"
  34. #include "UiTooltipDisplayComponent.h"
  35. #include "UiDynamicLayoutComponent.h"
  36. #include "UiDynamicScrollBoxComponent.h"
  37. #include "UiDropdownComponent.h"
  38. #include "UiDropdownOptionComponent.h"
  39. #include "Script/UiCanvasNotificationLuaBus.h"
  40. #include "Script/UiCanvasLuaBus.h"
  41. #include "Script/UiElementLuaBus.h"
  42. #include "Sprite.h"
  43. #include "UiSerialize.h"
  44. #include "UiRenderer.h"
  45. #include "Draw2d.h"
  46. #include <LyShine/Bus/UiCursorBus.h>
  47. #include <LyShine/Bus/UiDraggableBus.h>
  48. #include <LyShine/Bus/UiDropTargetBus.h>
  49. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  50. #include "TextMarkup.h"
  51. #endif
  52. #include <AzCore/Math/Crc.h>
  53. #include <AzCore/Component/ComponentApplicationBus.h>
  54. #include <AzCore/RTTI/BehaviorContext.h>
  55. #include <AzCore/Script/ScriptContextAttributes.h>
  56. #include <AzCore/Serialization/SerializeContext.h>
  57. #include <AzCore/Serialization/EditContext.h>
  58. #include <AzCore/Memory/PoolAllocator.h>
  59. #include <AzCore/Asset/AssetTypeInfoBus.h>
  60. #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
  61. #include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
  62. #include <AzFramework/Metrics/MetricsPlainTextNameRegistration.h>
  63. #include <Atom/RHI/RHIUtils.h>
  64. #include "Animation/UiAnimationSystem.h"
  65. #include "World/UiCanvasAssetRefComponent.h"
  66. #include "World/UiCanvasProxyRefComponent.h"
  67. #include "World/UiCanvasOnMeshComponent.h"
  68. //! \brief Simple utility class for LyShine functionality in Lua.
  69. //!
  70. //! Functionality unrelated to UI, such as showing the mouse cursor, should
  71. //! eventually be moved into other modules (for example, mouse cursor functionality
  72. //! should be moved to input, which matches more closely how FG modules are
  73. //! organized).
  74. class LyShineLua
  75. {
  76. public:
  77. static void ShowMouseCursor(bool visible)
  78. {
  79. static bool sShowCursor = false;
  80. if (visible)
  81. {
  82. if (!sShowCursor)
  83. {
  84. sShowCursor = true;
  85. UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter);
  86. }
  87. }
  88. else
  89. {
  90. if (sShowCursor)
  91. {
  92. sShowCursor = false;
  93. UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter);
  94. }
  95. }
  96. }
  97. };
  98. namespace AZ
  99. {
  100. AZ_TYPE_INFO_SPECIALIZE(LyShineLua, "{2570D3B3-2D18-4DB1-A0DE-E017A2F491D1}");
  101. }
  102. // This is the memory allocation for the static data member used for the debug console variables
  103. #ifndef _RELEASE
  104. AllocateConstIntCVar(CLyShine, CV_ui_DisplayTextureData);
  105. AllocateConstIntCVar(CLyShine, CV_ui_DisplayCanvasData);
  106. AllocateConstIntCVar(CLyShine, CV_ui_DisplayDrawCallData);
  107. AllocateConstIntCVar(CLyShine, CV_ui_DisplayElemBounds);
  108. AllocateConstIntCVar(CLyShine, CV_ui_DisplayElemBoundsCanvasIndex);
  109. #endif
  110. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  111. AllocateConstIntCVar(CLyShine, CV_ui_RunUnitTestsOnStartup);
  112. #endif
  113. ////////////////////////////////////////////////////////////////////////////////////////////////////
  114. CLyShine::CLyShine()
  115. : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityUI())
  116. , AzFramework::InputTextEventListener(AzFramework::InputTextEventListener::GetPriorityUI())
  117. , m_draw2d(new CDraw2d)
  118. , m_uiRenderer(new UiRenderer)
  119. , m_uiCanvasManager(new UiCanvasManager)
  120. , m_uiCursorVisibleCounter(0)
  121. {
  122. // Reflect the Deprecated Lua buses using the behavior context.
  123. // This support will be removed at some point
  124. {
  125. AZ::BehaviorContext* behaviorContext = nullptr;
  126. AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationBus::Events::GetBehaviorContext);
  127. if (behaviorContext)
  128. {
  129. behaviorContext->Class<LyShineLua>("LyShineLua")
  130. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  131. ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
  132. ->Method("ShowMouseCursor", &LyShineLua::ShowMouseCursor)
  133. ;
  134. UiCanvasNotificationLuaProxy::Reflect(behaviorContext);
  135. UiCanvasLuaProxy::Reflect(behaviorContext);
  136. UiElementLuaProxy::Reflect(behaviorContext);
  137. }
  138. }
  139. CSprite::Initialize();
  140. LyShineDebug::Initialize();
  141. UiElementComponent::Initialize();
  142. UiCanvasComponent::Initialize();
  143. AzFramework::InputChannelEventListener::Connect();
  144. AzFramework::InputTextEventListener::Connect();
  145. UiCursorBus::Handler::BusConnect();
  146. AZ::TickBus::Handler::BusConnect();
  147. AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(
  148. AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName());
  149. AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
  150. // These are internal Amazon components, so register them so that we can send back their names to our metrics collection
  151. // IF YOU ARE A THIRDPARTY WRITING A GEM, DO NOT REGISTER YOUR COMPONENTS WITH EditorMetricsComponentRegistrationBus
  152. // This is internal Amazon code, so register it's components for metrics tracking, otherwise the name of the component won't get sent back.
  153. AZStd::vector<AZ::Uuid> componentUuidsForMetricsCollection
  154. {
  155. azrtti_typeid<UiCanvasAssetRefComponent>(),
  156. azrtti_typeid<UiCanvasProxyRefComponent>(),
  157. azrtti_typeid<UiCanvasOnMeshComponent>(),
  158. azrtti_typeid<UiCanvasComponent>(),
  159. azrtti_typeid<UiElementComponent>(),
  160. azrtti_typeid<UiTransform2dComponent>(),
  161. azrtti_typeid<UiImageComponent>(),
  162. azrtti_typeid<UiTextComponent>(),
  163. azrtti_typeid<UiButtonComponent>(),
  164. azrtti_typeid<UiCheckboxComponent>(),
  165. azrtti_typeid<UiSliderComponent>(),
  166. azrtti_typeid<UiTextInputComponent>(),
  167. azrtti_typeid<UiScrollBarComponent>(),
  168. azrtti_typeid<UiScrollBoxComponent>(),
  169. azrtti_typeid<UiFaderComponent>(),
  170. azrtti_typeid<UiFlipbookAnimationComponent>(),
  171. azrtti_typeid<UiMarkupButtonComponent>(),
  172. azrtti_typeid<UiMaskComponent>(),
  173. azrtti_typeid<UiLayoutColumnComponent>(),
  174. azrtti_typeid<UiLayoutRowComponent>(),
  175. azrtti_typeid<UiLayoutGridComponent>(),
  176. azrtti_typeid<UiRadioButtonComponent>(),
  177. azrtti_typeid<UiRadioButtonGroupComponent>(),
  178. azrtti_typeid<UiDropdownComponent>(),
  179. azrtti_typeid<UiDropdownOptionComponent>(),
  180. azrtti_typeid<UiLayoutFitterComponent>(),
  181. azrtti_typeid<UiParticleEmitterComponent>(),
  182. };
  183. AzFramework::MetricsPlainTextNameRegistrationBus::Broadcast(
  184. &AzFramework::MetricsPlainTextNameRegistrationBus::Events::RegisterForNameSending, componentUuidsForMetricsCollection);
  185. #ifndef _RELEASE
  186. // Define a debug console variable that controls display of some debug info on UI texture usage
  187. DefineConstIntCVar3("ui_DisplayTextureData", CV_ui_DisplayTextureData, 0, VF_CHEAT,
  188. "0=off, 1=display info for all textures used in the frame");
  189. // Define a debug console variable that controls display of some debug info for all canvases
  190. DefineConstIntCVar3("ui_DisplayCanvasData", CV_ui_DisplayCanvasData, 0, VF_CHEAT,
  191. "0=off, 1=display info for all loaded UI canvases, 2=display info for all enabled UI canvases");
  192. // Define a debug console variable that controls display of some debug info on UI draw calls
  193. DefineConstIntCVar3("ui_DisplayDrawCallData", CV_ui_DisplayDrawCallData, 0, VF_CHEAT,
  194. "0=off, 1=display draw call info for all loaded and enabled UI canvases");
  195. // Define a debug console variable that controls display of all element bounds when in game
  196. DefineConstIntCVar3("ui_DisplayElemBounds", CV_ui_DisplayElemBounds, 0, VF_CHEAT,
  197. "0=off, 1=display the UI element bounding boxes");
  198. // Define a debug console variable that filters the display of all element bounds when in game by canvas index
  199. DefineConstIntCVar3("ui_DisplayElemBoundsCanvasIndex", CV_ui_DisplayElemBoundsCanvasIndex, -1, VF_CHEAT,
  200. "-1=no filter, 0-N=only for elements from this canvas index (see 'ui_displayCanvasData 2' for index)");
  201. // Define a console command that outputs a report to a file about the draw calls for all enabled canvases
  202. REGISTER_COMMAND("ui_ReportDrawCalls", &DebugReportDrawCalls, VF_NULL, "");
  203. #endif
  204. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  205. DefineConstIntCVar3("ui_RunUnitTestsOnStartup", CV_ui_RunUnitTestsOnStartup, 0, VF_CHEAT,
  206. "0=off, 1=run LyShine unit tests on startup");
  207. REGISTER_COMMAND("ui_RunUnitTests", &RunUnitTests, VF_NULL, "");
  208. #endif
  209. }
  210. ////////////////////////////////////////////////////////////////////////////////////////////////////
  211. CLyShine::~CLyShine()
  212. {
  213. UiCursorBus::Handler::BusDisconnect();
  214. AZ::TickBus::Handler::BusDisconnect();
  215. AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
  216. AzFramework::InputTextEventListener::Disconnect();
  217. AzFramework::InputChannelEventListener::Disconnect();
  218. AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
  219. LyShinePassDataRequestBus::Handler::BusDisconnect();
  220. UiCanvasComponent::Shutdown();
  221. // must be done after UiCanvasComponent::Shutdown
  222. CSprite::Shutdown();
  223. }
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////
  225. void CLyShine::Release()
  226. {
  227. delete this;
  228. }
  229. ////////////////////////////////////////////////////////////////////////////////////////////////////
  230. IDraw2d* CLyShine::GetDraw2d()
  231. {
  232. return m_draw2d.get();
  233. }
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////
  235. UiRenderer* CLyShine::GetUiRenderer()
  236. {
  237. return m_uiRenderer.get();
  238. }
  239. ////////////////////////////////////////////////////////////////////////////////////////////////////
  240. UiRenderer* CLyShine::GetUiRendererForEditor()
  241. {
  242. return m_uiRendererForEditor.get();
  243. }
  244. ////////////////////////////////////////////////////////////////////////////////////////////////////
  245. void CLyShine::SetUiRendererForEditor(AZStd::shared_ptr<UiRenderer> uiRenderer)
  246. {
  247. m_uiRendererForEditor = uiRenderer;
  248. }
  249. ////////////////////////////////////////////////////////////////////////////////////////////////////
  250. AZ::EntityId CLyShine::CreateCanvas()
  251. {
  252. return m_uiCanvasManager->CreateCanvas();
  253. }
  254. ////////////////////////////////////////////////////////////////////////////////////////////////////
  255. AZ::EntityId CLyShine::LoadCanvas(const AZStd::string& assetIdPathname)
  256. {
  257. return m_uiCanvasManager->LoadCanvas(assetIdPathname.c_str());
  258. }
  259. ////////////////////////////////////////////////////////////////////////////////////////////////////
  260. AZ::EntityId CLyShine::CreateCanvasInEditor(UiEntityContext* entityContext)
  261. {
  262. return m_uiCanvasManager->CreateCanvasInEditor(entityContext);
  263. }
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////
  265. AZ::EntityId CLyShine::LoadCanvasInEditor(const AZStd::string& assetIdPathname, const AZStd::string& sourceAssetPathname, UiEntityContext* entityContext)
  266. {
  267. return m_uiCanvasManager->LoadCanvasInEditor(assetIdPathname, sourceAssetPathname, entityContext);
  268. }
  269. ////////////////////////////////////////////////////////////////////////////////////////////////////
  270. AZ::EntityId CLyShine::ReloadCanvasFromXml(const AZStd::string& xmlString, UiEntityContext* entityContext)
  271. {
  272. return m_uiCanvasManager->ReloadCanvasFromXml(xmlString, entityContext);
  273. }
  274. ////////////////////////////////////////////////////////////////////////////////////////////////////
  275. AZ::EntityId CLyShine::FindCanvasById(LyShine::CanvasId id)
  276. {
  277. return m_uiCanvasManager->FindCanvasById(id);
  278. }
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////
  280. AZ::EntityId CLyShine::FindLoadedCanvasByPathName(const AZStd::string& assetIdPathname)
  281. {
  282. return m_uiCanvasManager->FindLoadedCanvasByPathName(assetIdPathname.c_str());
  283. }
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////
  285. void CLyShine::ReleaseCanvas(AZ::EntityId canvas, bool forEditor)
  286. {
  287. m_uiCanvasManager->ReleaseCanvas(canvas, forEditor);
  288. }
  289. ////////////////////////////////////////////////////////////////////////////////////////////////////
  290. void CLyShine::ReleaseCanvasDeferred(AZ::EntityId canvas)
  291. {
  292. m_uiCanvasManager->ReleaseCanvasDeferred(canvas);
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////////////////////////
  295. ISprite* CLyShine::LoadSprite(const AZStd::string& pathname)
  296. {
  297. return CSprite::LoadSprite(pathname);
  298. }
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////
  300. ISprite* CLyShine::CreateSprite(const AZ::Data::Asset<AZ::RPI::AttachmentImageAsset>& attachmentImageAsset)
  301. {
  302. return CSprite::CreateSprite(attachmentImageAsset);
  303. }
  304. ////////////////////////////////////////////////////////////////////////////////////////////////////
  305. bool CLyShine::DoesSpriteTextureAssetExist(const AZStd::string& pathname)
  306. {
  307. return CSprite::DoesSpriteTextureAssetExist(pathname);
  308. }
  309. ////////////////////////////////////////////////////////////////////////////////////////////////////
  310. AZ::Data::Instance<AZ::RPI::Image> CLyShine::LoadTexture(const AZStd::string& pathname)
  311. {
  312. return CDraw2d::LoadTexture(pathname);
  313. }
  314. ////////////////////////////////////////////////////////////////////////////////////////////////////
  315. void CLyShine::PostInit()
  316. {
  317. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  318. if (CV_ui_RunUnitTestsOnStartup)
  319. {
  320. RunUnitTests(nullptr);
  321. }
  322. #endif
  323. }
  324. ////////////////////////////////////////////////////////////////////////////////////////////////////
  325. void CLyShine::SetViewportSize(AZ::Vector2 viewportSize)
  326. {
  327. // Pass the viewport size to UiCanvasComponents
  328. m_uiCanvasManager->SetTargetSizeForLoadedCanvases(viewportSize);
  329. }
  330. ////////////////////////////////////////////////////////////////////////////////////////////////////
  331. void CLyShine::Update(float deltaTimeInSeconds)
  332. {
  333. if (!m_uiRenderer->IsReady())
  334. {
  335. return;
  336. }
  337. // Tell the UI system the size of the viewport we are rendering to - this drives the
  338. // canvas size for full screen UI canvases. It needs to be set before either lyShine->Update or
  339. // lyShine->Render are called. It must match the viewport size that the input system is using.
  340. SetViewportSize(m_uiRenderer->GetViewportSize());
  341. // Guard against nested updates. This can occur if a canvas update below triggers the load screen component's
  342. // UpdateAndRender (ex. when a texture is loaded)
  343. if (!m_updatingLoadedCanvases)
  344. {
  345. m_updatingLoadedCanvases = true;
  346. // Update all the canvases loaded in game
  347. m_uiCanvasManager->UpdateLoadedCanvases(deltaTimeInSeconds);
  348. // Execute events that have been queued during the canvas update
  349. ExecuteQueuedEvents();
  350. m_updatingLoadedCanvases = false;
  351. }
  352. }
  353. ////////////////////////////////////////////////////////////////////////////////////////////////////
  354. void CLyShine::Render()
  355. {
  356. if (AZ::RHI::IsNullRHI())
  357. {
  358. return;
  359. }
  360. if (m_updatingLoadedCanvases)
  361. {
  362. // Don't render if an update is in progress. This can occur if an update triggers the
  363. // load screen component's UpdateAndRender (ex. when a texture is loaded)
  364. return;
  365. }
  366. if (!m_uiRenderer->IsReady())
  367. {
  368. return;
  369. }
  370. #ifndef _RELEASE
  371. GetUiRenderer()->DebugSetRecordingOptionForTextureData(CV_ui_DisplayTextureData);
  372. #endif
  373. GetUiRenderer()->BeginUiFrameRender();
  374. // Render all the canvases loaded in game
  375. m_uiCanvasManager->RenderLoadedCanvases();
  376. // Set sort key for draw2d layer to ensure it renders in front of the canvases
  377. static const int64_t topLayerKey = 0x1000000;
  378. m_draw2d->SetSortKey(topLayerKey);
  379. m_draw2d->RenderDeferredPrimitives();
  380. // Don't render the UI cursor when in edit mode. For example during UI Preview mode a script could turn on the
  381. // cursor. But it would draw in the wrong place. It is better to just rely on the regular editor cursor in preview
  382. // since, in game, the game cursor could be turned on and off any any point, so each UI canvas is not necessarily
  383. // going to turn it on.
  384. if (!(gEnv->IsEditor() && gEnv->IsEditing()))
  385. {
  386. RenderUiCursor();
  387. }
  388. GetUiRenderer()->EndUiFrameRender();
  389. #ifndef _RELEASE
  390. if (CV_ui_DisplayElemBounds)
  391. {
  392. m_uiCanvasManager->DebugDisplayElemBounds(CV_ui_DisplayElemBoundsCanvasIndex);
  393. }
  394. if (CV_ui_DisplayTextureData)
  395. {
  396. GetUiRenderer()->DebugDisplayTextureData(CV_ui_DisplayTextureData);
  397. }
  398. else if (CV_ui_DisplayCanvasData)
  399. {
  400. m_uiCanvasManager->DebugDisplayCanvasData(CV_ui_DisplayCanvasData);
  401. }
  402. else if (CV_ui_DisplayDrawCallData)
  403. {
  404. m_uiCanvasManager->DebugDisplayDrawCallData();
  405. }
  406. #endif
  407. }
  408. ////////////////////////////////////////////////////////////////////////////////////////////////////
  409. void CLyShine::ExecuteQueuedEvents()
  410. {
  411. // Execute events that have been queued during the canvas update
  412. UiFaderNotificationBus::ExecuteQueuedEvents();
  413. UiAnimationNotificationBus::ExecuteQueuedEvents();
  414. // Execute events that have been queued during the input event handler
  415. UiDraggableNotificationBus::ExecuteQueuedEvents(); // draggable must be done before drop target
  416. UiDropTargetNotificationBus::ExecuteQueuedEvents();
  417. UiCanvasNotificationBus::ExecuteQueuedEvents();
  418. UiButtonNotificationBus::ExecuteQueuedEvents();
  419. UiInteractableNotificationBus::ExecuteQueuedEvents();
  420. }
  421. ////////////////////////////////////////////////////////////////////////////////////////////////////
  422. void CLyShine::Reset()
  423. {
  424. // This is called when the game is terminated.
  425. // Reset the debug module - this should be called before DestroyLoadedCanvases since it
  426. // tracks the loaded debug canvas
  427. LyShineDebug::Reset();
  428. // Delete all the canvases in m_canvases map that are not open in the editor.
  429. m_uiCanvasManager->DestroyLoadedCanvases(false);
  430. // Ensure that the UI Cursor is hidden.
  431. LyShineLua::ShowMouseCursor(false);
  432. m_uiCursorVisibleCounter = 0;
  433. }
  434. ////////////////////////////////////////////////////////////////////////////////////////////////////
  435. void CLyShine::OnLevelUnload()
  436. {
  437. // This is called when a level is unloaded or a new level is initialized
  438. // Reset the debug module - this should be called before DestroyLoadedCanvases since it
  439. // tracks the loaded debug canvas
  440. LyShineDebug::Reset();
  441. // Delete all the canvases in m_canvases map that a not loaded in the editor and are not
  442. // marked to be kept between levels.
  443. m_uiCanvasManager->DestroyLoadedCanvases(true);
  444. }
  445. ////////////////////////////////////////////////////////////////////////////////////////////////////
  446. void CLyShine::OnLoadScreenUnloaded()
  447. {
  448. m_uiCanvasManager->OnLoadScreenUnloaded();
  449. }
  450. ////////////////////////////////////////////////////////////////////////////////////////////////////
  451. void CLyShine::IncrementVisibleCounter()
  452. {
  453. ++m_uiCursorVisibleCounter;
  454. }
  455. ////////////////////////////////////////////////////////////////////////////////////////////////////
  456. void CLyShine::DecrementVisibleCounter()
  457. {
  458. --m_uiCursorVisibleCounter;
  459. }
  460. ////////////////////////////////////////////////////////////////////////////////////////////////////
  461. bool CLyShine::IsUiCursorVisible()
  462. {
  463. return m_uiCursorVisibleCounter > 0;
  464. }
  465. ////////////////////////////////////////////////////////////////////////////////////////////////////
  466. void CLyShine::SetUiCursor(const char* cursorImagePath)
  467. {
  468. m_uiCursorTexture.reset();
  469. m_cursorImagePathToLoad.clear();
  470. if (cursorImagePath && *cursorImagePath)
  471. {
  472. m_cursorImagePathToLoad = cursorImagePath;
  473. // The cursor image can only be loaded after the RPI has been initialized.
  474. // Note: this check could be avoided if LyShineSystemComponent included the RPISystem
  475. // as a required service. However, LyShineSystempComponent is currently activated for
  476. // tools as well as game and RPIService is not available with all tools such as AP. An
  477. // enhancement would be to break LyShineSystemComponent into a game only component
  478. if (m_uiRenderer->IsReady())
  479. {
  480. LoadUiCursor();
  481. }
  482. }
  483. }
  484. ////////////////////////////////////////////////////////////////////////////////////////////////////
  485. AZ::Vector2 CLyShine::GetUiCursorPosition()
  486. {
  487. AZ::Vector2 systemCursorPositionNormalized;
  488. AzFramework::InputSystemCursorRequestBus::EventResult(systemCursorPositionNormalized,
  489. AzFramework::InputDeviceMouse::Id,
  490. &AzFramework::InputSystemCursorRequests::GetSystemCursorPositionNormalized);
  491. AZ::Vector2 viewportSize = m_uiRenderer->GetViewportSize();
  492. return AZ::Vector2(systemCursorPositionNormalized.GetX() * viewportSize.GetX(),
  493. systemCursorPositionNormalized.GetY() * viewportSize.GetY());
  494. }
  495. void CLyShine::SetUiCursorPosition(const AZ::Vector2& positionNormalized)
  496. {
  497. AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::SetSystemCursorPositionNormalized, positionNormalized);
  498. }
  499. ////////////////////////////////////////////////////////////////////////////////////////////////////
  500. bool CLyShine::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
  501. {
  502. // disable UI inputs when console is open except for a primary release
  503. // if we ignore the primary release when there is an active interactable then it will miss its release
  504. // which leaves it in a bad state. E.g. a drag operation will be left in flight and not properly
  505. // terminated.
  506. if (gEnv->pConsole->GetStatus())
  507. {
  508. bool isPrimaryRelease = false;
  509. if (inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Button::Left ||
  510. inputChannel.GetInputChannelId() == AzFramework::InputDeviceTouch::Touch::Index0)
  511. {
  512. if (inputChannel.IsStateEnded())
  513. {
  514. isPrimaryRelease = true;
  515. }
  516. }
  517. if (!isPrimaryRelease)
  518. {
  519. return false;
  520. }
  521. }
  522. bool result = m_uiCanvasManager->HandleInputEventForLoadedCanvases(inputChannel);
  523. if (result)
  524. {
  525. // Execute events that have been queued during the input event handler
  526. ExecuteQueuedEvents();
  527. }
  528. return result;
  529. }
  530. ////////////////////////////////////////////////////////////////////////////////////////////////////
  531. bool CLyShine::OnInputTextEventFiltered(const AZStd::string& textUTF8)
  532. {
  533. if (gEnv->pConsole->GetStatus()) // disable UI inputs when console is open
  534. {
  535. return false;
  536. }
  537. bool result = m_uiCanvasManager->HandleTextEventForLoadedCanvases(textUTF8);
  538. if (result)
  539. {
  540. // Execute events that have been queued during the input event handler
  541. ExecuteQueuedEvents();
  542. }
  543. return result;
  544. }
  545. ////////////////////////////////////////////////////////////////////////////////////////////////////
  546. void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  547. {
  548. // Update the loaded UI canvases
  549. Update(deltaTime);
  550. }
  551. ////////////////////////////////////////////////////////////////////////////////////////////////////
  552. int CLyShine::GetTickOrder()
  553. {
  554. return AZ::TICK_PRE_RENDER;
  555. }
  556. ////////////////////////////////////////////////////////////////////////////////////////////////////
  557. void CLyShine::OnRenderTick()
  558. {
  559. // Recreate dirty render graphs and send primitive data to the dynamic draw context
  560. Render();
  561. }
  562. ////////////////////////////////////////////////////////////////////////////////////////////////////
  563. void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
  564. {
  565. // Load cursor if its path was set before RPI was initialized
  566. LoadUiCursor();
  567. LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId());
  568. }
  569. ////////////////////////////////////////////////////////////////////////////////////////////////////
  570. LyShine::AttachmentImagesAndDependencies CLyShine::GetRenderTargets()
  571. {
  572. LyShine::AttachmentImagesAndDependencies attachmentImagesAndDependencies;
  573. m_uiCanvasManager->GetRenderTargets(attachmentImagesAndDependencies);
  574. return attachmentImagesAndDependencies;
  575. }
  576. ////////////////////////////////////////////////////////////////////////////////////////////////////
  577. void CLyShine::LoadUiCursor()
  578. {
  579. if (!m_cursorImagePathToLoad.empty())
  580. {
  581. m_uiCursorTexture = CDraw2d::LoadTexture(m_cursorImagePathToLoad);
  582. m_cursorImagePathToLoad.clear();
  583. }
  584. }
  585. ////////////////////////////////////////////////////////////////////////////////////////////////////
  586. void CLyShine::RenderUiCursor()
  587. {
  588. if (!m_uiCursorTexture || !IsUiCursorVisible())
  589. {
  590. return;
  591. }
  592. const AzFramework::InputDevice* mouseDevice = AzFramework::InputDeviceRequests::FindInputDevice(AzFramework::InputDeviceMouse::Id);
  593. if (!mouseDevice || !mouseDevice->IsConnected())
  594. {
  595. return;
  596. }
  597. const AZ::Vector2 position = GetUiCursorPosition();
  598. AZ::RHI::Size cursorSize = m_uiCursorTexture->GetDescriptor().m_size;
  599. const AZ::Vector2 dimensions(aznumeric_cast<float>(cursorSize.m_width), aznumeric_cast<float>(cursorSize.m_height));
  600. IDraw2d::ImageOptions imageOptions;
  601. imageOptions.m_clamp = true;
  602. const float opacity = 1.0f;
  603. const float rotation = 0.0f;
  604. const AZ::Vector2* pivotPoint = nullptr;
  605. const AZ::Vector2* minMaxTexCoords = nullptr;
  606. m_draw2d->DrawImage(m_uiCursorTexture, position, dimensions, opacity, rotation, pivotPoint, minMaxTexCoords, &imageOptions);
  607. }
  608. #ifndef _RELEASE
  609. ////////////////////////////////////////////////////////////////////////////////////////////////////
  610. void CLyShine::DebugReportDrawCalls(IConsoleCmdArgs* cmdArgs)
  611. {
  612. if (AZ::Interface<ILyShine>::Get())
  613. {
  614. // We want to use an internal-only non-static function so downcast to CLyShine
  615. CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
  616. // There is an optional parameter which is a name to include in the output filename
  617. AZStd::string name;
  618. if (cmdArgs->GetArgCount() > 1)
  619. {
  620. name = cmdArgs->GetArg(1);
  621. }
  622. // Use the canvas manager to access all the loaded canvases
  623. lyShine->m_uiCanvasManager->DebugReportDrawCalls(name);
  624. }
  625. }
  626. #endif
  627. #if defined(LYSHINE_INTERNAL_UNIT_TEST)
  628. ////////////////////////////////////////////////////////////////////////////////////////////////////
  629. void CLyShine::RunUnitTests(IConsoleCmdArgs* cmdArgs)
  630. {
  631. // Tests are only valid from the launcher or from game mode (within the editor)
  632. const bool inEditorEnvironment = gEnv && gEnv->IsEditor() && gEnv->IsEditing();
  633. if (inEditorEnvironment)
  634. {
  635. AZ_Warning("LyShine", false,
  636. "Unit-tests: skipping! Editor environment detected. Run tests "
  637. "within editor via game mode (using ui_RunUnitTests) or use "
  638. "the standalone launcher instead.");
  639. return;
  640. }
  641. CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
  642. AZ_Assert(lyShine, "Attempting to run unit-tests prior to LyShine initialization!");
  643. TextMarkup::UnitTest(cmdArgs);
  644. UiTextComponent::UnitTest(lyShine, cmdArgs);
  645. UiTextComponent::UnitTestLocalization(lyShine, cmdArgs);
  646. UiTransform2dComponent::UnitTest(lyShine, cmdArgs);
  647. UiMarkupButtonComponent::UnitTest(lyShine, cmdArgs);
  648. }
  649. #endif