3
0

LyShineDebug.cpp 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  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 "LyShineDebug.h"
  9. #include "IConsole.h"
  10. #include <LyShine/IDraw2d.h>
  11. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  12. #include <AzCore/Math/Crc.h>
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <AzCore/Component/ComponentApplicationBus.h>
  15. #include <AzCore/Serialization/Utils.h>
  16. #include <LyShine/Bus/UiCanvasBus.h>
  17. #include <LyShine/ISprite.h>
  18. #include <LyShine/UiSerializeHelpers.h>
  19. #include <LyShine/Bus/UiElementBus.h>
  20. #include <LyShine/Bus/UiTransform2dBus.h>
  21. #include <LyShine/Bus/UiTextBus.h>
  22. #include <LyShine/Bus/UiImageBus.h>
  23. #include <LyShine/Bus/UiButtonBus.h>
  24. #include <LyShine/Bus/UiCheckboxBus.h>
  25. #include <LyShine/Bus/UiSliderBus.h>
  26. #include <LyShine/Bus/UiTextInputBus.h>
  27. #include <LyShine/Bus/UiInteractableStatesBus.h>
  28. #include <LyShine/Bus/UiInitializationBus.h>
  29. #include <LyShine/UiComponentTypes.h>
  30. AllocateConstIntCVar(LyShineDebug, CV_r_DebugUIDraw2dFont);
  31. AllocateConstIntCVar(LyShineDebug, CV_r_DebugUIDraw2dImage);
  32. AllocateConstIntCVar(LyShineDebug, CV_r_DebugUIDraw2dLine);
  33. AllocateConstIntCVar(LyShineDebug, CV_r_DebugUIDraw2dDefer);
  34. static const int g_numColors = 8;
  35. [[maybe_unused]] static const char* g_colorNames[g_numColors] =
  36. {
  37. "white",
  38. "red",
  39. "green",
  40. "blue",
  41. "yellow",
  42. "cyan",
  43. "magenta",
  44. "black"
  45. };
  46. [[maybe_unused]] static AZ::Vector3 g_colorVec3[g_numColors] =
  47. {
  48. AZ::Vector3(1.0f, 1.0f, 1.0f),
  49. AZ::Vector3(1.0f, 0.0f, 0.0f),
  50. AZ::Vector3(0.0f, 1.0f, 0.0f),
  51. AZ::Vector3(0.0f, 0.0f, 1.0f),
  52. AZ::Vector3(1.0f, 1.0f, 0.0f),
  53. AZ::Vector3(0.0f, 1.0f, 1.0f),
  54. AZ::Vector3(1.0f, 0.0f, 1.0f),
  55. AZ::Vector3(0.0f, 0.0f, 0.0f),
  56. };
  57. static const int g_numSrcBlendModes = 11;
  58. [[maybe_unused]] static AZ::RHI::BlendFactor g_srcBlendModes[g_numSrcBlendModes] =
  59. {
  60. AZ::RHI::BlendFactor::Zero,
  61. AZ::RHI::BlendFactor::One,
  62. AZ::RHI::BlendFactor::ColorDest,
  63. AZ::RHI::BlendFactor::ColorDestInverse,
  64. AZ::RHI::BlendFactor::AlphaSource,
  65. AZ::RHI::BlendFactor::AlphaSourceInverse,
  66. AZ::RHI::BlendFactor::AlphaDest,
  67. AZ::RHI::BlendFactor::AlphaDestInverse,
  68. AZ::RHI::BlendFactor::AlphaSourceSaturate,
  69. AZ::RHI::BlendFactor::Factor,
  70. AZ::RHI::BlendFactor::AlphaSource1
  71. };
  72. static const int g_numDstBlendModes = 10;
  73. [[maybe_unused]] static AZ::RHI::BlendFactor g_dstBlendModes[g_numDstBlendModes] =
  74. {
  75. AZ::RHI::BlendFactor::Zero,
  76. AZ::RHI::BlendFactor::One,
  77. AZ::RHI::BlendFactor::ColorSource,
  78. AZ::RHI::BlendFactor::ColorSourceInverse,
  79. AZ::RHI::BlendFactor::AlphaSource,
  80. AZ::RHI::BlendFactor::AlphaSourceInverse,
  81. AZ::RHI::BlendFactor::AlphaDest,
  82. AZ::RHI::BlendFactor::AlphaDestInverse,
  83. AZ::RHI::BlendFactor::FactorInverse,
  84. AZ::RHI::BlendFactor::AlphaSource1Inverse
  85. };
  86. [[maybe_unused]] static bool g_deferDrawsToEndOfFrame = false;
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////
  88. // LOCAL STATIC FUNCTIONS
  89. ////////////////////////////////////////////////////////////////////////////////////////////////////
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////
  91. #if !defined(_RELEASE)
  92. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  93. static int Create2DTexture(int width, int height, byte* data, ETEX_Format format)
  94. {
  95. IRenderer* renderer = gEnv->pRenderer;
  96. return renderer->DownLoadToVideoMemory(data, width, height, format, format, 1);
  97. }
  98. #endif
  99. #endif
  100. #if !defined(_RELEASE)
  101. static AZ::Vector2 GetTextureSize(AZ::Data::Instance<AZ::RPI::Image> image)
  102. {
  103. AZ::RHI::Size size = image->GetDescriptor().m_size;
  104. return AZ::Vector2(static_cast<float>(size.m_width), static_cast<float>(size.m_height));
  105. }
  106. #endif
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////
  108. #if !defined(_RELEASE)
  109. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  110. static void FillTextureRectWithCheckerboard(uint32* data, int textureWidth, int textureHeight,
  111. int minX, int minY, [[maybe_unused]] int rectWidth, int rectHeight,
  112. int tileWidth, int tileHeight, uint32* colors, bool varyAlpha)
  113. {
  114. for (int i = minX; i < minX + rectHeight && i < textureWidth; ++i)
  115. {
  116. for (int j = minY; j < minY + rectHeight && j < textureHeight; ++j)
  117. {
  118. // if both even then colors[0], if one even & one odd then colors[1], if both odd then colors[2]
  119. int index = ((i / tileWidth) % 2) + ((j / tileHeight) % 2);
  120. uint32 color = colors[index];
  121. if (varyAlpha)
  122. {
  123. // across y we fade the alpha from 0 at top to 1 at bottom
  124. uint32 alpha = (j - minY) * 255 / rectHeight;
  125. color = (color & 0x00ffffff) | (alpha << 24);
  126. }
  127. data[i + j * textureWidth] = color;
  128. }
  129. }
  130. }
  131. #endif
  132. #endif
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////
  134. #if !defined(_RELEASE)
  135. static AZ::Data::Instance<AZ::RPI::Image> CreateMonoTestTexture()
  136. {
  137. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  138. const int width = 32;
  139. const int height = 32;
  140. uint32 data[width * height];
  141. const uint32 black = 0xff000000;
  142. const uint32 grey = 0xff7f7f7f;
  143. const uint32 white = 0xffffffff;
  144. uint32 colors[3] = {black, grey, white};
  145. // create a checker board
  146. // top left quadrant, change every pixel
  147. FillTextureRectWithCheckerboard(data, width, height, 0, 0, width / 2, height / 2,
  148. 1, 1, colors, false);
  149. // top right quadrant, change every 2 pixels
  150. FillTextureRectWithCheckerboard(data, width, height, width / 2, 0, width / 2, height / 2,
  151. 2, 2, colors, false);
  152. // bottom right quadrant, change every 4 pixels
  153. FillTextureRectWithCheckerboard(data, width, height, width / 2, height / 2, width / 2, height / 2,
  154. 4, 4, colors, false);
  155. // bottom left quadrant, change every 8 pixels
  156. FillTextureRectWithCheckerboard(data, width, height, 0, height / 2, width / 2, height / 2,
  157. 8, 8, colors, false);
  158. int textureId = Create2DTexture(width, height, (uint8*)data, eTF_R8G8B8A8);
  159. return gEnv->pRenderer->EF_GetTextureByID(textureId);
  160. #else
  161. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  162. return whiteTexture;
  163. #endif
  164. }
  165. #endif
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////
  167. #if !defined(_RELEASE)
  168. static AZ::Data::Instance<AZ::RPI::Image> CreateColorTestTexture()
  169. {
  170. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  171. const int width = 32;
  172. const int height = 32;
  173. uint32 data[width * height];
  174. const uint32 red = 0xffff0000;
  175. const uint32 green = 0xff00ff00;
  176. const uint32 blue = 0xff0000ff;
  177. uint32 colors[3] = { red, green, blue };
  178. // create a checker board
  179. // top left quadrant, change every pixel
  180. FillTextureRectWithCheckerboard(data, width, height, 0, 0, width / 2, height / 2,
  181. 1, 1, colors, false);
  182. // top right quadrant, change every 2 pixels
  183. FillTextureRectWithCheckerboard(data, width, height, width / 2, 0, width / 2, height / 2,
  184. 2, 2, colors, false);
  185. // bottom right quadrant, change every 4 pixels
  186. FillTextureRectWithCheckerboard(data, width, height, width / 2, height / 2, width / 2, height / 2,
  187. 4, 4, colors, false);
  188. // bottom left quadrant, change every 8 pixels
  189. FillTextureRectWithCheckerboard(data, width, height, 0, height / 2, width / 2, height / 2,
  190. 8, 8, colors, false);
  191. int textureId = Create2DTexture(width, height, (uint8*)data, eTF_R8G8B8A8);
  192. return gEnv->pRenderer->EF_GetTextureByID(textureId);
  193. #else
  194. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  195. return whiteTexture;
  196. #endif
  197. }
  198. #endif
  199. ////////////////////////////////////////////////////////////////////////////////////////////////////
  200. #if !defined(_RELEASE)
  201. static AZ::Data::Instance<AZ::RPI::Image> CreateMonoAlphaTestTexture()
  202. {
  203. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  204. const int width = 32;
  205. const int height = 32;
  206. uint32 data[width * height];
  207. const uint32 black = 0xff000000;
  208. const uint32 grey = 0xff7f7f7f;
  209. const uint32 white = 0xffffffff;
  210. uint32 colors[3] = { black, grey, white };
  211. // create a checker board
  212. // top left quadrant, change every pixel
  213. FillTextureRectWithCheckerboard(data, width, height, 0, 0, width / 2, height / 2,
  214. 1, 1, colors, true);
  215. // top right quadrant, change every 2 pixels
  216. FillTextureRectWithCheckerboard(data, width, height, width / 2, 0, width / 2, height / 2,
  217. 2, 2, colors, true);
  218. // bottom right quadrant, change every 4 pixels
  219. FillTextureRectWithCheckerboard(data, width, height, width / 2, height / 2, width / 2, height / 2,
  220. 4, 4, colors, true);
  221. // bottom left quadrant, change every 8 pixels
  222. FillTextureRectWithCheckerboard(data, width, height, 0, height / 2, width / 2, height / 2,
  223. 8, 8, colors, true);
  224. int textureId = Create2DTexture(width, height, (uint8*)data, eTF_R8G8B8A8);
  225. return gEnv->pRenderer->EF_GetTextureByID(textureId);
  226. #else
  227. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  228. return whiteTexture;
  229. #endif
  230. }
  231. #endif
  232. ////////////////////////////////////////////////////////////////////////////////////////////////////
  233. #if !defined(_RELEASE)
  234. static AZ::Data::Instance<AZ::RPI::Image> CreateColorAlphaTestTexture()
  235. {
  236. #ifdef LYSHINE_ATOM_TODO // [GHI #6270] Support RTT using Atom
  237. const int width = 32;
  238. const int height = 32;
  239. uint32 data[width * height];
  240. const uint32 red = 0x00ff0000;
  241. const uint32 green = 0x0000ff00;
  242. const uint32 blue = 0x000000ff;
  243. uint32 colors[3] = { red, green, blue };
  244. // create a checker board
  245. // top left quadrant, change every pixel
  246. FillTextureRectWithCheckerboard(data, width, height, 0, 0, width / 2, height / 2,
  247. 1, 1, colors, true);
  248. // top right quadrant, change every 2 pixels
  249. FillTextureRectWithCheckerboard(data, width, height, width / 2, 0, width / 2, height / 2,
  250. 2, 2, colors, true);
  251. // bottom right quadrant, change every 4 pixels
  252. FillTextureRectWithCheckerboard(data, width, height, width / 2, height / 2, width / 2, height / 2,
  253. 4, 4, colors, true);
  254. // bottom left quadrant, change every 8 pixels
  255. FillTextureRectWithCheckerboard(data, width, height, 0, height / 2, width / 2, height / 2,
  256. 8, 8, colors, true);
  257. int textureId = Create2DTexture(width, height, (uint8*)data, eTF_R8G8B8A8);
  258. return gEnv->pRenderer->EF_GetTextureByID(textureId);
  259. #else
  260. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  261. return whiteTexture;
  262. #endif
  263. }
  264. #endif
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////
  266. #if !defined(_RELEASE)
  267. static AZ::Data::Instance<AZ::RPI::Image> GetMonoTestTexture()
  268. {
  269. static AZ::Data::Instance<AZ::RPI::Image> testImageMono = nullptr;
  270. if (!testImageMono)
  271. {
  272. testImageMono = CreateMonoTestTexture();
  273. }
  274. return testImageMono;
  275. }
  276. #endif
  277. ////////////////////////////////////////////////////////////////////////////////////////////////////
  278. #if !defined(_RELEASE)
  279. static AZ::Data::Instance<AZ::RPI::Image> GetColorTestTexture()
  280. {
  281. static AZ::Data::Instance<AZ::RPI::Image> testImageColor = nullptr;
  282. if (!testImageColor)
  283. {
  284. testImageColor = CreateColorTestTexture();
  285. }
  286. return testImageColor;
  287. }
  288. #endif
  289. ////////////////////////////////////////////////////////////////////////////////////////////////////
  290. #if !defined(_RELEASE)
  291. static AZ::Data::Instance<AZ::RPI::Image> GetMonoAlphaTestTexture()
  292. {
  293. static AZ::Data::Instance<AZ::RPI::Image> testImageMonoAlpha = nullptr;
  294. if (!testImageMonoAlpha)
  295. {
  296. testImageMonoAlpha = CreateMonoAlphaTestTexture();
  297. }
  298. return testImageMonoAlpha;
  299. }
  300. #endif
  301. ////////////////////////////////////////////////////////////////////////////////////////////////////
  302. #if !defined(_RELEASE)
  303. static AZ::Data::Instance<AZ::RPI::Image> GetColorAlphaTestTexture()
  304. {
  305. static AZ::Data::Instance<AZ::RPI::Image> testImageColorAlpha = nullptr;
  306. if (!testImageColorAlpha)
  307. {
  308. testImageColorAlpha = CreateColorAlphaTestTexture();
  309. }
  310. return testImageColorAlpha;
  311. }
  312. #endif
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////
  314. #if !defined(_RELEASE)
  315. static void DebugDrawColoredBox(AZ::Vector2 pos, AZ::Vector2 size, AZ::Color color,
  316. IDraw2d::HAlign horizontalAlignment = IDraw2d::HAlign::Left,
  317. IDraw2d::VAlign verticalAlignment = IDraw2d::VAlign::Top)
  318. {
  319. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  320. IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions();
  321. imageOptions.color = color.GetAsVector3();
  322. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  323. draw2d->DrawImageAligned(whiteTexture, pos, size, horizontalAlignment, verticalAlignment,
  324. color.GetA(), 0.0f, nullptr, &imageOptions);
  325. }
  326. #endif
  327. ////////////////////////////////////////////////////////////////////////////////////////////////////
  328. #if !defined(_RELEASE)
  329. static void DebugDrawStringWithSizeBox(AZStd::string_view font, unsigned int effectIndex, const char* sizeString,
  330. const char* testString, AZ::Vector2 pos, float spacing, float size)
  331. {
  332. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  333. IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions();
  334. if (!font.empty())
  335. {
  336. textOptions.fontName = font;
  337. }
  338. textOptions.effectIndex = effectIndex;
  339. draw2d->DrawText(sizeString, pos, size, 1.0f, &textOptions);
  340. AZ::Vector2 sizeTextSize = draw2d->GetTextSize(sizeString, size, &textOptions);
  341. AZ::Vector2 testTextSize = draw2d->GetTextSize(testString, size, &textOptions);
  342. AZ::Vector2 pos2(pos.GetX() + sizeTextSize.GetX() + spacing, pos.GetY());
  343. DebugDrawColoredBox(AZ::Vector2(pos2.GetX() - 1, pos2.GetY() - 1), AZ::Vector2(testTextSize.GetX() + 2, testTextSize.GetY() + 2),
  344. AZ::Color(0.5f, 0.5f, 0.5f, 1.0f));
  345. DebugDrawColoredBox(pos2, testTextSize, AZ::Color(0.0f, 0.0f, 0.0f, 1.0f));
  346. draw2d->DrawText(testString, pos2, size, 1.0f, &textOptions);
  347. AZ::Vector2 pos3(pos2.GetX() + testTextSize.GetX() + spacing, pos.GetY());
  348. char buffer[32];
  349. sprintf_s(buffer, "Pixel height = %5.2f", testTextSize.GetY());
  350. AZ::Vector2 pixelHeightTextSize = draw2d->GetTextSize(buffer, size, &textOptions);
  351. // Draw a light background to see if there is a drop shadow
  352. DebugDrawColoredBox(AZ::Vector2(pos3.GetX() - 1, pos3.GetY() - 1),
  353. AZ::Vector2(pixelHeightTextSize.GetX() + 2, pixelHeightTextSize.GetY() + 2),
  354. AZ::Color(0.65f, 0.65f, 0.65f, 1.0f));
  355. draw2d->DrawText(buffer, pos3, size, 1.0f, &textOptions);
  356. }
  357. #endif
  358. ////////////////////////////////////////////////////////////////////////////////////////////////////
  359. #if !defined(_RELEASE)
  360. static void DebugDraw2dFontSizes(AZStd::string_view font, unsigned int effectIndex)
  361. {
  362. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  363. float xOffset = 20.0f;
  364. float yOffset = 20.0f;
  365. float xSpacing = 20.0f;
  366. char buffer[32];
  367. sprintf_s(buffer, "Font = %s, effect = %d", font.data(), effectIndex);
  368. draw2d->DrawText(buffer, AZ::Vector2(xOffset, yOffset), 32);
  369. yOffset += 40.0f;
  370. draw2d->DrawText("NOTE: if the effect includes a drop shadow baked into font then the pixel size",
  371. AZ::Vector2(xOffset, yOffset), 16);
  372. draw2d->DrawText("NOTE: The pixel height reported takes no account of the actual characters used.",
  373. AZ::Vector2(xOffset + draw2d->GetViewportWidth() * 0.5f, yOffset), 16);
  374. yOffset += 20.0f;
  375. draw2d->DrawText("will include the drop shadow offset.", AZ::Vector2(xOffset, yOffset), 16);
  376. yOffset += 20.0f;
  377. const char* testString = "AbdfhkltgjpqyWw|01!";
  378. const char* minimalTestString = "ace";
  379. DebugDrawStringWithSizeBox(font, effectIndex, "Size 16", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 16);
  380. DebugDrawStringWithSizeBox(font, effectIndex, "Size 16", minimalTestString,
  381. AZ::Vector2(xOffset + draw2d->GetViewportWidth() * 0.5f, yOffset), xSpacing, 16);
  382. yOffset += 40.0f;
  383. DebugDrawStringWithSizeBox(font, effectIndex, "Size 17", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 17);
  384. yOffset += 40.0f;
  385. DebugDrawStringWithSizeBox(font, effectIndex, "Size 18", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 18);
  386. yOffset += 40.0f;
  387. DebugDrawStringWithSizeBox(font, effectIndex, "Size 23", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 23);
  388. yOffset += 40.0f;
  389. DebugDrawStringWithSizeBox(font, effectIndex, "Size 24", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 24);
  390. yOffset += 40.0f;
  391. DebugDrawStringWithSizeBox(font, effectIndex, "Size 25", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 25);
  392. yOffset += 40.0f;
  393. DebugDrawStringWithSizeBox(font, effectIndex, "Size 30", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 30);
  394. yOffset += 40.0f;
  395. DebugDrawStringWithSizeBox(font, effectIndex, "Size 31", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 31);
  396. yOffset += 40.0f;
  397. DebugDrawStringWithSizeBox(font, effectIndex, "Size 32", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 32);
  398. yOffset += 40.0f;
  399. DebugDrawStringWithSizeBox(font, effectIndex, "Size 33", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 33);
  400. yOffset += 40.0f;
  401. DebugDrawStringWithSizeBox(font, effectIndex, "Size 34", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 34);
  402. yOffset += 40.0f;
  403. DebugDrawStringWithSizeBox(font, effectIndex, "Size 47", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 47);
  404. yOffset += 55.0f;
  405. DebugDrawStringWithSizeBox(font, effectIndex, "Size 48", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 48);
  406. yOffset += 55.0f;
  407. DebugDrawStringWithSizeBox(font, effectIndex, "Size 49", testString, AZ::Vector2(xOffset, yOffset), xSpacing, 49);
  408. }
  409. #endif
  410. ////////////////////////////////////////////////////////////////////////////////////////////////////
  411. #if !defined(_RELEASE)
  412. static void DebugDrawAlignedTextWithOriginBox(AZ::Vector2 pos,
  413. IDraw2d::HAlign horizontalAlignment,
  414. IDraw2d::VAlign verticalAlignment, float pointSize, AZ::Vector3 textColor)
  415. {
  416. Draw2dHelper draw2d(g_deferDrawsToEndOfFrame);
  417. const char* haStr = 0;
  418. const char* vaStr = 0;
  419. switch (horizontalAlignment)
  420. {
  421. case IDraw2d::HAlign::Left:
  422. haStr = "Left";
  423. break;
  424. case IDraw2d::HAlign::Center:
  425. haStr = "Center";
  426. break;
  427. case IDraw2d::HAlign::Right:
  428. haStr = "Right";
  429. break;
  430. }
  431. switch (verticalAlignment)
  432. {
  433. case IDraw2d::VAlign::Top:
  434. vaStr = "Top";
  435. break;
  436. case IDraw2d::VAlign::Center:
  437. vaStr = "Center";
  438. break;
  439. case IDraw2d::VAlign::Bottom:
  440. vaStr = "Bottom";
  441. break;
  442. }
  443. char buffer[64];
  444. sprintf_s(buffer, "%s %s, size=%5.2f", haStr, vaStr, pointSize);
  445. AZ::Color backgroundColor(0.3f, 0.3f, 0.3f, 1.0f);
  446. DebugDrawColoredBox(pos, draw2d.GetTextSize(buffer, pointSize), backgroundColor,
  447. horizontalAlignment, verticalAlignment);
  448. AZ::Color boxColor(1.0f, 0.25f, 0.25f, 1.0f);
  449. DebugDrawColoredBox(AZ::Vector2(pos.GetX() - 2.0f, pos.GetY() - 2.0f), AZ::Vector2(5.0f, 5.0f), boxColor);
  450. draw2d.SetTextAlignment(horizontalAlignment, verticalAlignment);
  451. draw2d.SetTextColor(textColor);
  452. draw2d.DrawText(buffer, pos, pointSize, 1.0f);
  453. }
  454. #endif
  455. ////////////////////////////////////////////////////////////////////////////////////////////////////
  456. #if !defined(_RELEASE)
  457. static void DebugDraw2dFontAlignment()
  458. {
  459. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  460. float w = draw2d->GetViewportWidth();
  461. float yPos = 20;
  462. {
  463. Draw2dHelper draw2dHelper(g_deferDrawsToEndOfFrame);
  464. draw2dHelper.DrawText(
  465. "Text Alignment. Red dot is the pos passed to DrawText. Default font, effect 0",
  466. AZ::Vector2(20, yPos), 16);
  467. yPos += 20;
  468. }
  469. AZ::Vector3 color1(1, 1, 1);
  470. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  471. IDraw2d::HAlign::Left, IDraw2d::VAlign::Top, 32, color1);
  472. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  473. IDraw2d::HAlign::Center, IDraw2d::VAlign::Top, 32, color1);
  474. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  475. IDraw2d::HAlign::Right, IDraw2d::VAlign::Top, 32, color1);
  476. yPos += 60;
  477. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  478. IDraw2d::HAlign::Left, IDraw2d::VAlign::Center, 32, color1);
  479. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  480. IDraw2d::HAlign::Center, IDraw2d::VAlign::Center, 32, color1);
  481. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  482. IDraw2d::HAlign::Right, IDraw2d::VAlign::Center, 32, color1);
  483. yPos += 60;
  484. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  485. IDraw2d::HAlign::Left, IDraw2d::VAlign::Bottom, 32, color1);
  486. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  487. IDraw2d::HAlign::Center, IDraw2d::VAlign::Bottom, 32, color1);
  488. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  489. IDraw2d::HAlign::Right, IDraw2d::VAlign::Bottom, 32, color1);
  490. AZ::Vector3 color2(0.25f, 0.5f, 1.0f);
  491. yPos += 30;
  492. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  493. IDraw2d::HAlign::Left, IDraw2d::VAlign::Top, 24, color2);
  494. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  495. IDraw2d::HAlign::Center, IDraw2d::VAlign::Top, 24, color2);
  496. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  497. IDraw2d::HAlign::Right, IDraw2d::VAlign::Top, 24, color2);
  498. yPos += 50;
  499. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  500. IDraw2d::HAlign::Left, IDraw2d::VAlign::Center, 24, color2);
  501. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  502. IDraw2d::HAlign::Center, IDraw2d::VAlign::Center, 24, color2);
  503. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  504. IDraw2d::HAlign::Right, IDraw2d::VAlign::Center, 24, color2);
  505. yPos += 50;
  506. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(20, yPos),
  507. IDraw2d::HAlign::Left, IDraw2d::VAlign::Bottom, 24, color2);
  508. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w / 2, yPos),
  509. IDraw2d::HAlign::Center, IDraw2d::VAlign::Bottom, 24, color2);
  510. DebugDrawAlignedTextWithOriginBox(AZ::Vector2(w - 20, yPos),
  511. IDraw2d::HAlign::Right, IDraw2d::VAlign::Bottom, 24, color2);
  512. }
  513. #endif
  514. ////////////////////////////////////////////////////////////////////////////////////////////////////
  515. #if !defined(_RELEASE)
  516. static AZ::Vector2 DebugDrawFontColorTestBox(AZ::Vector2 pos, const char* string, AZ::Vector3 color, float opacity)
  517. {
  518. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  519. float pointSize = 32.0f;
  520. const float spacing = 6.0f;
  521. IDraw2d::TextOptions textOptions = draw2d->GetDefaultTextOptions();
  522. textOptions.effectIndex = 1; // no drop shadow baked in
  523. textOptions.color = color;
  524. AZ::Vector2 textSize = draw2d->GetTextSize(string, pointSize, &textOptions);
  525. AZ::Vector2 totalBackgroundSize(textSize.GetX() + spacing * 2.0f, textSize.GetY() + spacing * 4.0f);
  526. AZ::Vector2 whiteBackgroundSize(totalBackgroundSize.GetX() * 0.5f, totalBackgroundSize.GetY());
  527. AZ::Vector2 blackBackgroundSize = whiteBackgroundSize;
  528. AZ::Vector2 whiteBackgroundPos = pos;
  529. AZ::Vector2 blackBackgroundPos = pos + AZ::Vector2(whiteBackgroundSize.GetX(), 0);
  530. AZ::Vector2 textPos = pos + AZ::Vector2(spacing, spacing);
  531. AZ::Vector2 boxPos = pos + AZ::Vector2(spacing, spacing + textSize.GetY() + spacing);
  532. DebugDrawColoredBox(whiteBackgroundPos, whiteBackgroundSize, AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
  533. DebugDrawColoredBox(blackBackgroundPos, blackBackgroundSize, AZ::Color(0.0f, 0.0f, 0.0f, 1.0f));
  534. draw2d->DrawText(string, textPos, pointSize, opacity, &textOptions);
  535. DebugDrawColoredBox(boxPos, AZ::Vector2(textSize.GetX(), spacing), AZ::Color::CreateFromVector3AndFloat(color, opacity));
  536. return totalBackgroundSize;
  537. }
  538. #endif
  539. ////////////////////////////////////////////////////////////////////////////////////////////////////
  540. #if !defined(_RELEASE)
  541. static void DebugDraw2dFontColorAndOpacity()
  542. {
  543. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  544. AZ::Vector2 size;
  545. AZ::Vector2 pos(20.0f, 20.0f);
  546. for (int color = 0; color < g_numColors; ++color)
  547. {
  548. AZ::Vector2 boxPos = pos;
  549. size = DebugDrawFontColorTestBox(boxPos, g_colorNames[color], g_colorVec3[color], 1.0f);
  550. boxPos.SetX(boxPos.GetX() + 200.0f);
  551. size = DebugDrawFontColorTestBox(boxPos, g_colorNames[color], g_colorVec3[color], 0.75f);
  552. boxPos.SetX(boxPos.GetX() + 200.0f);
  553. size = DebugDrawFontColorTestBox(boxPos, g_colorNames[color], g_colorVec3[color], 0.5f);
  554. boxPos.SetX(boxPos.GetX() + 200.0f);
  555. size = DebugDrawFontColorTestBox(boxPos, g_colorNames[color], g_colorVec3[color], 0.25f);
  556. boxPos.SetX(boxPos.GetX() + 200.0f);
  557. size = DebugDrawFontColorTestBox(boxPos, g_colorNames[color], g_colorVec3[color], 0.00f);
  558. pos.SetY(pos.GetY() + size.GetY() + 10.0f);
  559. }
  560. draw2d->DrawText("Opacity=1.00f", pos, 24.0f);
  561. pos.SetX(pos.GetX() + 200.0f);
  562. draw2d->DrawText("Opacity=0.75f", pos, 24.0f);
  563. pos.SetX(pos.GetX() + 200.0f);
  564. draw2d->DrawText("Opacity=0.50f", pos, 24.0f);
  565. pos.SetX(pos.GetX() + 200.0f);
  566. draw2d->DrawText("Opacity=0.25f", pos, 24.0f);
  567. pos.SetX(pos.GetX() + 200.0f);
  568. draw2d->DrawText("Opacity=0.00f", pos, 24.0f);
  569. }
  570. #endif
  571. ////////////////////////////////////////////////////////////////////////////////////////////////////
  572. #if !defined(_RELEASE)
  573. static void DebugDraw2dImageRotations()
  574. {
  575. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  576. AZ::Data::Instance<AZ::RPI::Image> texture = GetMonoTestTexture();
  577. AZ::Vector2 size = GetTextureSize(texture);
  578. float row = 20.0f;
  579. float xSpacing = size.GetX() * 2.0f;
  580. float xStart = 50.0f;
  581. AZ::Color posBoxColor(1.0f, 0.25f, 0.25f, 1.0f);
  582. AZ::Color pivotBoxColor(1.0f, 1.00f, 0.00f, 1.0f);
  583. draw2d->DrawText("No pivot, rotation about pos (drawn in red), increments of 45 degrees", AZ::Vector2(xStart, row), 16);
  584. row += 16 + 60.0f;
  585. for (int i = 0; i < 10; ++i)
  586. {
  587. AZ::Vector2 pos(xStart + xSpacing * i, row);
  588. draw2d->DrawImage(texture, pos, size, 1.0f, 45.0f * i);
  589. DebugDrawColoredBox(AZ::Vector2(pos.GetX() - 2, pos.GetY() - 2), AZ::Vector2(5, 5), posBoxColor);
  590. }
  591. row += 60.0f;
  592. draw2d->DrawText("Rotation about pivot. Pos drawn in red, pivot is yellow. Increments of 45 degrees",
  593. AZ::Vector2(xStart, row), 16);
  594. row += 16 + 40.0f;
  595. AZ::Vector2 pivotOffset(10, 20);
  596. for (int i = 0; i < 10; ++i)
  597. {
  598. AZ::Vector2 pos(xStart + xSpacing * i, row);
  599. AZ::Vector2 pivot = pos + pivotOffset;
  600. draw2d->DrawImage(texture, pos, size, 1.0f, 45.0f * i, &pivot);
  601. DebugDrawColoredBox(AZ::Vector2(pos.GetX() - 2, pos.GetY() - 2), AZ::Vector2(5, 5), posBoxColor);
  602. DebugDrawColoredBox(AZ::Vector2(pivot.GetX() - 2, pivot.GetY() - 2), AZ::Vector2(5, 5), pivotBoxColor);
  603. }
  604. row += 100.0f;
  605. draw2d->DrawText("DrawImageAligned (center,center). Pos drawn in red. Increments of 45 degrees",
  606. AZ::Vector2(xStart, row), 16);
  607. row += 16 + 30.0f;
  608. for (int i = 0; i < 10; ++i)
  609. {
  610. AZ::Vector2 pos(xStart + xSpacing * i + size.GetX() * 0.5f, row + size.GetY() * 0.5f);
  611. draw2d->DrawImageAligned(texture, pos, size, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center, 1.0f, 45.0f * i);
  612. DebugDrawColoredBox(AZ::Vector2(pos.GetX() - 2, pos.GetY() - 2), AZ::Vector2(5, 5), posBoxColor);
  613. }
  614. }
  615. #endif
  616. ////////////////////////////////////////////////////////////////////////////////////////////////////
  617. #if !defined(_RELEASE)
  618. static void DebugDraw2dImageColor()
  619. {
  620. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  621. AZ::Data::Instance<AZ::RPI::Image> texture = GetMonoAlphaTestTexture();
  622. IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions();
  623. draw2d->DrawText(
  624. "Testing image colors, image is black and white, top row is opacity=1, bottom row is opacity = 0.5",
  625. AZ::Vector2(20, 20), 16);
  626. AZ::Vector2 size = GetTextureSize(texture) * 2.0f;
  627. float xStart = 20.0f;
  628. float yStart = 50.0f;
  629. float xSpacing = size.GetX() + 20.0f;
  630. float ySpacing = size.GetY() + 20.0f;
  631. for (int color = 0; color < g_numColors; ++color)
  632. {
  633. AZ::Vector2 pos(xStart + xSpacing * color, yStart);
  634. // Draw the image with this color
  635. imageOptions.color = g_colorVec3[color];
  636. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, 0, &imageOptions);
  637. // draw below with half opacity to test combination of color and opacity
  638. pos.SetY(pos.GetY() + ySpacing);
  639. draw2d->DrawImage(texture, pos, size, 0.5f, 0.0f, 0, 0, &imageOptions);
  640. }
  641. }
  642. #endif
  643. ////////////////////////////////////////////////////////////////////////////////////////////////////
  644. #if !defined(_RELEASE)
  645. static void DebugDraw2dImageBlendMode()
  646. {
  647. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  648. auto whiteTexture = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  649. AZ::Data::Instance<AZ::RPI::Image> texture = GetColorAlphaTestTexture();
  650. IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions();
  651. draw2d->DrawText("Testing blend modes, src blend changes across x-axis, dst blend changes across y axis",
  652. AZ::Vector2(20, 20), 16);
  653. AZ::Vector2 size = GetTextureSize(texture);
  654. float width = size.GetX();
  655. float height = size.GetY();
  656. float xStart = 20.0f;
  657. float yStart = 60.0f;
  658. float xSpacing = width + 2.0f;
  659. float ySpacing = height + 2.0f;
  660. for (int srcIndex = 0; srcIndex < g_numSrcBlendModes; ++srcIndex)
  661. {
  662. for (int dstIndex = 0; dstIndex < g_numDstBlendModes; ++dstIndex)
  663. {
  664. AZ::Vector2 pos(xStart + xSpacing * srcIndex, yStart + ySpacing * dstIndex);
  665. // first draw a background with varying color and alpha
  666. IDraw2d::VertexPosColUV verts[4] =
  667. {
  668. { // top left
  669. AZ::Vector2(pos.GetX(), pos.GetY()),
  670. AZ::Color(1.0f, 0.0f, 0.0f, 1.0f),
  671. AZ::Vector2(0.0f, 0.0f)
  672. },
  673. { // top right
  674. AZ::Vector2(pos.GetX() + width, pos.GetY()),
  675. AZ::Color(0.0f, 1.0f, 0.0f, 1.0f),
  676. AZ::Vector2(1.0f, 0.0f)
  677. },
  678. { // bottom right
  679. AZ::Vector2(pos.GetX() + width, pos.GetY() + height),
  680. AZ::Color(1.0f, 1.0f, 1.0f, 0.0f),
  681. AZ::Vector2(1.0f, 1.0f)
  682. },
  683. { // bottom left
  684. AZ::Vector2(pos.GetX(), pos.GetY() + height),
  685. AZ::Color(0.0f, 0.0f, 1.0f, 1.0f),
  686. AZ::Vector2(0.0f, 1.0f)
  687. },
  688. };
  689. draw2d->DrawQuad(whiteTexture, verts);
  690. // Draw the image with this color
  691. IDraw2d::RenderState renderState;
  692. renderState.m_blendState.m_blendSource = g_srcBlendModes[srcIndex];
  693. renderState.m_blendState.m_blendDest = g_dstBlendModes[dstIndex];
  694. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, 0, &imageOptions);
  695. }
  696. }
  697. }
  698. #endif
  699. ////////////////////////////////////////////////////////////////////////////////////////////////////
  700. #if !defined(_RELEASE)
  701. static void DebugDraw2dImageUVs()
  702. {
  703. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  704. AZ::Data::Instance<AZ::RPI::Image> texture = GetColorTestTexture();
  705. draw2d->DrawText(
  706. "Testing DrawImage with minMaxTexCoords. Full image, top left quadrant, middle section, full flipped",
  707. AZ::Vector2(20, 20), 16);
  708. AZ::Vector2 size = GetTextureSize(texture) * 2.0f;
  709. float xStart = 20.0f;
  710. float yStart = 50.0f;
  711. float xSpacing = size.GetX() + 20.0f;
  712. AZ::Vector2 pos(xStart, yStart);
  713. AZ::Vector2 minMaxTexCoords[2];
  714. // full image
  715. minMaxTexCoords[0] = AZ::Vector2(0, 0);
  716. minMaxTexCoords[1] = AZ::Vector2(1, 1);
  717. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, minMaxTexCoords);
  718. // top left quadrant of image
  719. pos.SetX(pos.GetX() + xSpacing);
  720. minMaxTexCoords[0] = AZ::Vector2(0, 0);
  721. minMaxTexCoords[1] = AZ::Vector2(0.5, 0.5);
  722. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, minMaxTexCoords);
  723. // middle of image
  724. pos.SetX(pos.GetX() + xSpacing);
  725. minMaxTexCoords[0] = AZ::Vector2(0.25, 0.25);
  726. minMaxTexCoords[1] = AZ::Vector2(0.75, 0.75);
  727. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, minMaxTexCoords);
  728. // flip of image
  729. pos.SetX(pos.GetX() + xSpacing);
  730. minMaxTexCoords[0] = AZ::Vector2(0.0, 1.0);
  731. minMaxTexCoords[1] = AZ::Vector2(1.0, 0.0);
  732. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, minMaxTexCoords);
  733. }
  734. #endif
  735. ////////////////////////////////////////////////////////////////////////////////////////////////////
  736. #if !defined(_RELEASE)
  737. static void DebugDraw2dImagePixelRounding()
  738. {
  739. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  740. AZ::Data::Instance<AZ::RPI::Image> texture = GetColorTestTexture();
  741. IDraw2d::ImageOptions imageOptions = draw2d->GetDefaultImageOptions();
  742. draw2d->DrawText("Testing DrawImage pixel rounding options", AZ::Vector2(20, 20), 16);
  743. AZ::Vector2 size = GetTextureSize(texture);
  744. float xStart = 20.0f;
  745. float yStart = 50.0f;
  746. float xSpacing = size.GetX() + 4.0f;
  747. float ySpacing = size.GetY() + 4.0f;
  748. float offsets[4] = { 0.0f, 0.17f, 0.5f, 0.67f };
  749. IDraw2d::Rounding roundings[4] = {
  750. IDraw2d::Rounding::None,
  751. IDraw2d::Rounding::Nearest,
  752. IDraw2d::Rounding::Down,
  753. IDraw2d::Rounding::Up
  754. };
  755. for (int i = 0; i < 4; ++i) // loop through pixel offsets (along x axis)
  756. {
  757. for (int j = 0; j < 4; ++j) // loop through rounding options (along y axis)
  758. {
  759. AZ::Vector2 pos(xStart + xSpacing * i + offsets[i], yStart + ySpacing * j + offsets[i]);
  760. imageOptions.pixelRounding = roundings[j];
  761. draw2d->DrawImage(texture, pos, size, 1.0f, 0.0f, 0, 0, &imageOptions);
  762. }
  763. }
  764. }
  765. #endif
  766. ////////////////////////////////////////////////////////////////////////////////////////////////////
  767. #if !defined(_RELEASE)
  768. static void DebugDraw2dLineBasic()
  769. {
  770. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  771. draw2d->DrawText("Testing DrawLine", AZ::Vector2(20, 20), 16);
  772. AZ::Vector2 center = AZ::Vector2(draw2d->GetViewportWidth() * 0.5f, draw2d->GetViewportHeight() * 0.5f);
  773. float offset = 300.0f;
  774. AZ::Color white(1.0f, 1.0f, 1.0f, 1.0f);
  775. draw2d->DrawLine(center, center + AZ::Vector2(offset, 0), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
  776. draw2d->DrawLine(center, center + AZ::Vector2(offset, offset), AZ::Color(1.0f, 0.0f, 0.0f, 1.0f));
  777. draw2d->DrawLine(center, center + AZ::Vector2(0, offset), AZ::Color(1.0f, 1.0f, 0.0f, 1.0f));
  778. draw2d->DrawLine(center, center + AZ::Vector2(-offset, offset), AZ::Color(0.0f, 1.0f, 0.0f, 1.0f));
  779. draw2d->DrawLine(center, center + AZ::Vector2(-offset, 0), AZ::Color(0.0f, 1.0f, 1.0f, 1.0f));
  780. draw2d->DrawLine(center, center + AZ::Vector2(-offset, -offset), AZ::Color(0.0f, 0.0f, 1.0f, 1.0f));
  781. draw2d->DrawLine(center, center + AZ::Vector2(0, -offset), AZ::Color(1.0f, 0.0f, 1.0f, 1.0f));
  782. draw2d->DrawLine(center, center + AZ::Vector2(offset, -offset), AZ::Color(0.0f, 0.0f, 0.0f, 1.0f));
  783. }
  784. #endif
  785. static AZ::EntityId g_testCanvasId;
  786. static void CreateComponent(AZ::Entity* entity, const AZ::Uuid& componentTypeId)
  787. {
  788. entity->Deactivate();
  789. entity->CreateComponent(componentTypeId);
  790. entity->Activate();
  791. }
  792. ////////////////////////////////////////////////////////////////////////////////////////////////////
  793. static AZ::Entity* CreateButton(const char* name, bool atRoot, AZ::EntityId parent,
  794. UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
  795. const char* text, AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor, AZ::Color textColor)
  796. {
  797. AZ::Entity* buttonElem = nullptr;
  798. if (atRoot)
  799. {
  800. UiCanvasBus::EventResult(buttonElem, parent, &UiCanvasBus::Events::CreateChildElement, name);
  801. }
  802. else
  803. {
  804. UiElementBus::EventResult(buttonElem, parent, &UiElementBus::Events::CreateChildElement, name);
  805. }
  806. {
  807. AZ::EntityId buttonId = buttonElem->GetId();
  808. // create components for button elem
  809. CreateComponent(buttonElem, LyShine::UiTransform2dComponentUuid);
  810. CreateComponent(buttonElem, LyShine::UiImageComponentUuid);
  811. CreateComponent(buttonElem, LyShine::UiButtonComponentUuid);
  812. AZ_Assert(UiTransform2dBus::FindFirstHandler(buttonId), "Transform2d component missing");
  813. UiTransform2dBus::Event(buttonId, &UiTransform2dBus::Events::SetAnchors, anchors, false, false);
  814. UiTransform2dBus::Event(buttonId, &UiTransform2dBus::Events::SetOffsets, offsets);
  815. UiImageBus::Event(buttonId, &UiImageBus::Events::SetColor, baseColor);
  816. UiInteractableStatesBus::Event(
  817. buttonId, &UiInteractableStatesBus::Events::SetStateColor, UiInteractableStatesInterface::StateHover, buttonId, selectedColor);
  818. UiInteractableStatesBus::Event(
  819. buttonId,
  820. &UiInteractableStatesBus::Events::SetStateAlpha,
  821. UiInteractableStatesInterface::StateHover,
  822. buttonId,
  823. selectedColor.GetA());
  824. UiInteractableStatesBus::Event(
  825. buttonId, &UiInteractableStatesBus::Events::SetStateColor, UiInteractableStatesInterface::StatePressed, buttonId, pressedColor);
  826. UiInteractableStatesBus::Event(
  827. buttonId,
  828. &UiInteractableStatesBus::Events::SetStateAlpha,
  829. UiInteractableStatesInterface::StatePressed,
  830. buttonId,
  831. pressedColor.GetA());
  832. AZStd::string pathname = "Textures/Basic/Button_Sliced_Normal.sprite";
  833. ISprite* sprite = AZ::Interface<ILyShine>::Get()->LoadSprite(pathname);
  834. UiImageBus::Event(buttonId, &UiImageBus::Events::SetSprite, sprite);
  835. UiImageBus::Event(buttonId, &UiImageBus::Events::SetImageType, UiImageInterface::ImageType::Sliced);
  836. }
  837. {
  838. // create child text element for the button
  839. AZ::Entity* textElem = nullptr;
  840. UiElementBus::EventResult(textElem, buttonElem->GetId(), &UiElementBus::Events::CreateChildElement, "ButtonText");
  841. AZ::EntityId textId = textElem->GetId();
  842. CreateComponent(textElem, LyShine::UiTransform2dComponentUuid);
  843. CreateComponent(textElem, LyShine::UiTextComponentUuid);
  844. AZ_Assert(UiTransform2dBus::FindFirstHandler(textId), "Transform component missing");
  845. UiTransform2dBus::Event(
  846. textId, &UiTransform2dBus::Events::SetAnchors, UiTransform2dInterface::Anchors(0.5, 0.5, 0.5, 0.5), false, false);
  847. UiTransform2dBus::Event(textId, &UiTransform2dBus::Events::SetOffsets, UiTransform2dInterface::Offsets(0, 0, 0, 0));
  848. UiTextBus::Event(textId, &UiTextBus::Events::SetText, text);
  849. UiTextBus::Event(textId, &UiTextBus::Events::SetTextAlignment, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
  850. UiTextBus::Event(textId, &UiTextBus::Events::SetColor, textColor);
  851. UiTextBus::Event(textId, &UiTextBus::Events::SetFontSize, 24.0f);
  852. }
  853. return buttonElem;
  854. }
  855. ////////////////////////////////////////////////////////////////////////////////////////////////////
  856. static AZ::Entity* CreateText(const char* name, bool atRoot, AZ::EntityId parent,
  857. UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
  858. const char* text, AZ::Color textColor, IDraw2d::HAlign hAlign, IDraw2d::VAlign vAlign)
  859. {
  860. // create a text
  861. AZ::Entity* textElem = nullptr;
  862. if (atRoot)
  863. {
  864. UiCanvasBus::EventResult(textElem, parent, &UiCanvasBus::Events::CreateChildElement, name);
  865. }
  866. else
  867. {
  868. UiElementBus::EventResult(textElem, parent, &UiElementBus::Events::CreateChildElement, name);
  869. }
  870. AZ_Assert(textElem, "Failed to create child element for text");
  871. AZ::EntityId textId = textElem->GetId();
  872. CreateComponent(textElem, LyShine::UiTransform2dComponentUuid);
  873. CreateComponent(textElem, LyShine::UiTextComponentUuid);
  874. AZ_Assert(UiTransform2dBus::FindFirstHandler(textId), "Transform component missing");
  875. UiTransform2dBus::Event(textId, &UiTransform2dBus::Events::SetAnchors, anchors, false, false);
  876. UiTransform2dBus::Event(textId, &UiTransform2dBus::Events::SetOffsets, offsets);
  877. UiTextBus::Event(textId, &UiTextBus::Events::SetText, text);
  878. UiTextBus::Event(textId, &UiTextBus::Events::SetTextAlignment, hAlign, vAlign);
  879. UiTextBus::Event(textId, &UiTextBus::Events::SetColor, textColor);
  880. return textElem;
  881. }
  882. ////////////////////////////////////////////////////////////////////////////////////////////////////
  883. static AZ::Entity* CreateTextInput(const char* name, bool atRoot, AZ::EntityId parent,
  884. UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
  885. const char* text, const char* placeHolderText,
  886. AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor,
  887. AZ::Color textColor, AZ::Color placeHolderColor)
  888. {
  889. AZ::Entity* textInputElem = nullptr;
  890. if (atRoot)
  891. {
  892. UiCanvasBus::EventResult(textInputElem, parent, &UiCanvasBus::Events::CreateChildElement, name);
  893. }
  894. else
  895. {
  896. UiElementBus::EventResult(textInputElem, parent, &UiElementBus::Events::CreateChildElement, name);
  897. }
  898. {
  899. AZ::EntityId textInputId = textInputElem->GetId();
  900. // create components for text input element
  901. CreateComponent(textInputElem, LyShine::UiTransform2dComponentUuid);
  902. CreateComponent(textInputElem, LyShine::UiImageComponentUuid);
  903. CreateComponent(textInputElem, LyShine::UiTextInputComponentUuid);
  904. AZ_Assert(UiTransform2dBus::FindFirstHandler(textInputId), "Transform2d component missing");
  905. UiTransform2dBus::Event(textInputId, &UiTransform2dBus::Events::SetAnchors, anchors, false, false);
  906. UiTransform2dBus::Event(textInputId, &UiTransform2dBus::Events::SetOffsets, offsets);
  907. UiImageBus::Event(textInputId, &UiImageBus::Events::SetColor, baseColor);
  908. UiInteractableStatesBus::Event(
  909. textInputId,
  910. &UiInteractableStatesBus::Events::SetStateColor,
  911. UiInteractableStatesInterface::StateHover,
  912. textInputId,
  913. selectedColor);
  914. UiInteractableStatesBus::Event(
  915. textInputId,
  916. &UiInteractableStatesBus::Events::SetStateAlpha,
  917. UiInteractableStatesInterface::StateHover,
  918. textInputId,
  919. selectedColor.GetA());
  920. UiInteractableStatesBus::Event(
  921. textInputId,
  922. &UiInteractableStatesBus::Events::SetStateColor,
  923. UiInteractableStatesInterface::StatePressed,
  924. textInputId,
  925. pressedColor);
  926. UiInteractableStatesBus::Event(
  927. textInputId,
  928. &UiInteractableStatesBus::Events::SetStateAlpha,
  929. UiInteractableStatesInterface::StatePressed,
  930. textInputId,
  931. pressedColor.GetA());
  932. AZStd::string pathname = "Textures/Basic/Button_Sliced_Normal.sprite";
  933. ISprite* sprite = AZ::Interface<ILyShine>::Get()->LoadSprite(pathname);
  934. UiImageBus::Event(textInputId, &UiImageBus::Events::SetSprite, sprite);
  935. UiImageBus::Event(textInputId, &UiImageBus::Events::SetImageType, UiImageInterface::ImageType::Sliced);
  936. }
  937. // create child text element
  938. AZ::Entity* textElem = CreateText("Text", false, textInputElem->GetId(),
  939. UiTransform2dInterface::Anchors(0.0f, 0.0f, 1.0f, 1.0f),
  940. UiTransform2dInterface::Offsets(5.0f, 5.0f, -5.0f, -5.00f),
  941. text, textColor, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
  942. // reduce the font size
  943. UiTextBus::Event(textElem->GetId(), &UiTextBus::Events::SetFontSize, 24.0f);
  944. // now link the textInputComponent to the child text entity
  945. UiTextInputBus::Event(textInputElem->GetId(), &UiTextInputBus::Events::SetTextEntity, textElem->GetId());
  946. // create child placeholder text element
  947. AZ::Entity* placeHolderElem = CreateText("PlaceholderText", false, textInputElem->GetId(),
  948. UiTransform2dInterface::Anchors(0.0f, 0.0f, 1.0f, 1.0f),
  949. UiTransform2dInterface::Offsets(5.0f, 5.0f, -5.0f, -5.00f),
  950. placeHolderText, placeHolderColor, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
  951. // reduce the font size
  952. UiTextBus::Event(placeHolderElem->GetId(), &UiTextBus::Events::SetFontSize, 24.0f);
  953. // now link the textInputComponent to the child placeholder text entity
  954. UiTextInputBus::Event(textInputElem->GetId(), &UiTextInputBus::Events::SetPlaceHolderTextEntity, placeHolderElem->GetId());
  955. // Trigger all InGamePostActivate
  956. UiInitializationBus::Event(textInputElem->GetId(), &UiInitializationBus::Events::InGamePostActivate);
  957. UiInitializationBus::Event(textElem->GetId(), &UiInitializationBus::Events::InGamePostActivate);
  958. UiInitializationBus::Event(placeHolderElem->GetId(), &UiInitializationBus::Events::InGamePostActivate);
  959. return textInputElem;
  960. }
  961. ////////////////////////////////////////////////////////////////////////////////////////////////////
  962. // Very simple test class implementing IUiCanvasActionListener
  963. // This just calls the callback passed into the constructor
  964. namespace
  965. {
  966. class ActionListener
  967. : public UiCanvasNotificationBus::Handler
  968. {
  969. public:
  970. ActionListener(AZ::EntityId canvasId, LyShine::ActionName actionName, AZStd::function<void(void)> fn)
  971. : m_canvasId(canvasId)
  972. , m_actionName(actionName)
  973. , m_fn(fn)
  974. {
  975. UiCanvasNotificationBus::Handler::BusConnect(m_canvasId);
  976. }
  977. ~ActionListener()
  978. {
  979. Unregister();
  980. }
  981. void OnAction([[maybe_unused]] AZ::EntityId canvasId, const LyShine::ActionName& actionName) override
  982. {
  983. if (actionName == m_actionName)
  984. {
  985. m_fn();
  986. }
  987. }
  988. void Unregister()
  989. {
  990. if (m_canvasId.IsValid())
  991. {
  992. UiCanvasNotificationBus::Handler::BusDisconnect(m_canvasId);
  993. }
  994. }
  995. private:
  996. AZ::EntityId m_canvasId;
  997. LyShine::ActionName m_actionName;
  998. AZStd::function<void(void)> m_fn;
  999. };
  1000. }
  1001. static ActionListener* g_testActionListener1 = nullptr;
  1002. static ActionListener* g_testActionListener2 = nullptr;
  1003. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1004. static void DestroyTestCanvas()
  1005. {
  1006. if (g_testCanvasId.IsValid())
  1007. {
  1008. delete g_testActionListener1;
  1009. g_testActionListener1 = nullptr;
  1010. delete g_testActionListener2;
  1011. g_testActionListener2 = nullptr;
  1012. AZ::Interface<ILyShine>::Get()->ReleaseCanvas(g_testCanvasId, false);
  1013. g_testCanvasId.SetInvalid();
  1014. }
  1015. }
  1016. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1017. static void TestCanvasCreate ([[maybe_unused]] IConsoleCmdArgs* Cmd)
  1018. {
  1019. if (gEnv->IsEditing())
  1020. {
  1021. return;
  1022. }
  1023. const AZ::Color grey(.3f, .3f, .4f, .5f);
  1024. const AZ::Color blue(.2f, .3f, 1.f, 1.f);
  1025. const AZ::Color red(1.f, .1f, .1f, 1.f);
  1026. const AZ::Color pink(1.f, .5f, .5f, 1.f);
  1027. const AZ::Color white(1.f, 1.f, 1.f, 1.f);
  1028. const AZ::Color yellow(1.f, 1.f, 0.f, 1.f);
  1029. // remove the existing test canvas if it exists
  1030. DestroyTestCanvas();
  1031. // test creation of canvas and some simple elements
  1032. AZ::EntityId canvasEntityId = AZ::Interface<ILyShine>::Get()->CreateCanvas();
  1033. UiCanvasInterface* canvas = UiCanvasBus::FindFirstHandler(canvasEntityId);
  1034. if (!canvas)
  1035. {
  1036. return;
  1037. }
  1038. g_testCanvasId = canvasEntityId;
  1039. // create an image to be the menu background
  1040. AZ::Entity* pauseMenuElem = canvas->CreateChildElement("Menu1");
  1041. CreateComponent(pauseMenuElem, LyShine::UiTransform2dComponentUuid);
  1042. CreateComponent(pauseMenuElem, LyShine::UiImageComponentUuid);
  1043. AZ::EntityId pauseMenuId = pauseMenuElem->GetId();
  1044. AZ_Assert(UiTransform2dBus::FindFirstHandler(pauseMenuId), "Transform component missing");
  1045. UiTransform2dBus::Event(
  1046. pauseMenuId, &UiTransform2dBus::Events::SetAnchors, UiTransform2dInterface::Anchors(0.25, 0.25, 0.75, 0.75), false, false);
  1047. UiTransform2dBus::Event(pauseMenuId, &UiTransform2dBus::Events::SetOffsets, UiTransform2dInterface::Offsets(0, 0, 0, 0));
  1048. UiImageBus::Event(pauseMenuId, &UiImageBus::Events::SetColor, grey);
  1049. // create a title, centered at top of menu
  1050. CreateText("Heading", false, pauseMenuId, UiTransform2dInterface::Anchors(0.5f, 0.0f, 0.5f, 0.0f), UiTransform2dInterface::Offsets(0, 20, 0, 50),
  1051. "Pause Menu", yellow, IDraw2d::HAlign::Center, IDraw2d::VAlign::Top);
  1052. // create a test text at left top
  1053. CreateText("TopLeftText", false, pauseMenuId, UiTransform2dInterface::Anchors(0.0f, 0.0f, 0.0f, 0.0f), UiTransform2dInterface::Offsets(0, 0, 50, 50),
  1054. "LT", yellow, IDraw2d::HAlign::Left, IDraw2d::VAlign::Top);
  1055. // create a test text at left center
  1056. CreateText("CenterLeftText", false, pauseMenuId, UiTransform2dInterface::Anchors(0.0f, 0.5f, 0.0f, 0.5f), UiTransform2dInterface::Offsets(0, -25, 50, 25),
  1057. "LC", yellow, IDraw2d::HAlign::Left, IDraw2d::VAlign::Center);
  1058. // create a test text at left bottom
  1059. CreateText("BottomLeftText", false, pauseMenuId, UiTransform2dInterface::Anchors(0.0f, 1.0f, 0.0f, 1.0f), UiTransform2dInterface::Offsets(0, -50, 50, 0),
  1060. "LB", yellow, IDraw2d::HAlign::Left, IDraw2d::VAlign::Bottom);
  1061. // create a test text at center bottom
  1062. CreateText("BottomCenterText", false, pauseMenuId, UiTransform2dInterface::Anchors(0.5f, 1.0f, 0.5f, 1.0f), UiTransform2dInterface::Offsets(-25, -50, 25, 0),
  1063. "CB", yellow, IDraw2d::HAlign::Center, IDraw2d::VAlign::Bottom);
  1064. // create a test text at center bottom
  1065. CreateText("CenterRightText", false, pauseMenuId, UiTransform2dInterface::Anchors(1.0f, 1.0f, 1.0f, 1.0f), UiTransform2dInterface::Offsets(-50, -50, 0, 0),
  1066. "CR", yellow, IDraw2d::HAlign::Right, IDraw2d::VAlign::Bottom);
  1067. // Create a "Show Image" button
  1068. [[maybe_unused]] AZ::Entity* showImageButtonElem = CreateButton("ShowImage", false, pauseMenuId,
  1069. UiTransform2dInterface::Anchors(0.5, 0.5, 0.5, 0.5), UiTransform2dInterface::Offsets(-120.0f, -25.0f, 120.0f, 25.0f),
  1070. "Show Image", blue, pink, red, white);
  1071. // Create a "Hide Image" button
  1072. CreateButton("HideImage", false, pauseMenuId,
  1073. UiTransform2dInterface::Anchors(0.5f, 1.0f, 0.5f, 1.0f), UiTransform2dInterface::Offsets(-120.0f, -100.0f, 120.0f, -50.0f),
  1074. "Hide Image", blue, pink, red, white);
  1075. // Create a "Enter name" text input element
  1076. AZ::Color colGreenYellow(0.678f, 1.000f, 0.184f, 1.0f);
  1077. AZ::Entity* textInputElem = CreateTextInput("EnterName", false, pauseMenuId,
  1078. UiTransform2dInterface::Anchors(0.5f, 0.0f, 0.5f, 0.0f), UiTransform2dInterface::Offsets(-120.0f, 70.0f, 120.0f, 120.0f),
  1079. "", "Enter Name", blue, pink, red, white, colGreenYellow);
  1080. // Create an image that these buttons will show/hide
  1081. // create an image to be the menu background
  1082. AZ::Entity* testImageElem = canvas->CreateChildElement("TestImage");
  1083. CreateComponent(testImageElem, LyShine::UiTransform2dComponentUuid);
  1084. CreateComponent(testImageElem, LyShine::UiImageComponentUuid);
  1085. UiTransform2dBus::Event(
  1086. testImageElem->GetId(),
  1087. &UiTransform2dBus::Events::SetAnchors,
  1088. UiTransform2dInterface::Anchors(0.78f, 0.25f, 0.95f, 0.75f),
  1089. false,
  1090. false);
  1091. UiTransform2dBus::Event(
  1092. testImageElem->GetId(), &UiTransform2dBus::Events::SetOffsets, UiTransform2dInterface::Offsets(0.0f, 0.0f, 0.0f, 0.0f));
  1093. UiImageBus::Event(testImageElem->GetId(), &UiImageBus::Events::SetColor, yellow);
  1094. // create some text items that the textInputItem will edit,
  1095. AZ::Color colGreen(0.000f, 0.502f, 0.000f, 1.0f);
  1096. AZ::Entity* changedTextElem = CreateText("ChangedText", true, canvasEntityId, UiTransform2dInterface::Anchors(0.8f, 0.30f, 0.93f, 0.30f), UiTransform2dInterface::Offsets(0.0f, 0.0f, 0.0f, 50.0f),
  1097. "Changed Text", colGreen, IDraw2d::HAlign::Center, IDraw2d::VAlign::Top);
  1098. AZ::Entity* editedTextElem = CreateText("EditedText", true, canvasEntityId, UiTransform2dInterface::Anchors(0.8f, 0.40f, 0.93f, 0.40f), UiTransform2dInterface::Offsets(0.0f, 0.0f, 0.0f, 50.0f),
  1099. "Edited Text", colGreen, IDraw2d::HAlign::Center, IDraw2d::VAlign::Top);
  1100. AZ::Entity* enteredTextElem = CreateText("EnteredText", true, canvasEntityId, UiTransform2dInterface::Anchors(0.8f, 0.50f, 0.93f, 0.50f), UiTransform2dInterface::Offsets(0.0f, 0.0f, 0.0f, 50.0f),
  1101. "Entered Text", colGreen, IDraw2d::HAlign::Center, IDraw2d::VAlign::Top);
  1102. // now setup on-click callbacks to hide and show the menus, use the various ways of doing it
  1103. // First button uses a simple callback
  1104. AZ::Entity* buttonElem = nullptr;
  1105. UiElementBus::EventResult(buttonElem, pauseMenuId, &UiElementBus::Events::FindDescendantByName, "ShowImage");
  1106. auto setEnabledCallbackFn = [testImageElem]([[maybe_unused]] AZ::EntityId clickedEntityId, [[maybe_unused]] AZ::Vector2 point)
  1107. {
  1108. UiElementBus::Event(testImageElem->GetId(), &UiElementBus::Events::SetIsEnabled, true);
  1109. };
  1110. UiButtonBus::Event(buttonElem->GetId(), &UiButtonBus::Events::SetOnClickCallback, setEnabledCallbackFn);
  1111. // Second button uses an ActionListener
  1112. UiElementBus::EventResult(buttonElem, pauseMenuId, &UiElementBus::Events::FindDescendantByName, "HideImage");
  1113. LyShine::ActionName actionName1("ShowImage");
  1114. auto setDisabledActionFn = [testImageElem](void)
  1115. {
  1116. UiElementBus::Event(testImageElem->GetId(), &UiElementBus::Events::SetIsEnabled, false);
  1117. };
  1118. g_testActionListener1 = new ActionListener(canvasEntityId, actionName1, setDisabledActionFn);
  1119. UiButtonBus::Event(buttonElem->GetId(), &UiButtonBus::Events::SetOnClickActionName, actionName1);
  1120. // Setup callbacks for the text input field
  1121. auto setChangedTextFn = [changedTextElem]([[maybe_unused]] AZ::EntityId textInputEntityId, LyShine::StringType textString)
  1122. {
  1123. UiTextBus::Event(changedTextElem->GetId(), &UiTextBus::Events::SetText, textString);
  1124. };
  1125. auto setEditedTextFn = [editedTextElem]([[maybe_unused]] AZ::EntityId textInputEntityId, LyShine::StringType textString)
  1126. {
  1127. UiTextBus::Event(editedTextElem->GetId(), &UiTextBus::Events::SetText, textString);
  1128. };
  1129. auto setEnteredTextFn = [enteredTextElem]([[maybe_unused]] AZ::EntityId textInputEntityId, LyShine::StringType textString)
  1130. {
  1131. UiTextBus::Event(enteredTextElem->GetId(), &UiTextBus::Events::SetText, textString);
  1132. };
  1133. UiTextInputBus::Event(textInputElem->GetId(), &UiTextInputBus::Events::SetOnChangeCallback, setChangedTextFn);
  1134. UiTextInputBus::Event(textInputElem->GetId(), &UiTextInputBus::Events::SetOnEndEditCallback, setEditedTextFn);
  1135. UiTextInputBus::Event(textInputElem->GetId(), &UiTextInputBus::Events::SetOnEnterCallback, setEnteredTextFn);
  1136. // test clone feature by cloning the whole pause menu
  1137. AZ::Entity* clonedMenuElem = nullptr;
  1138. UiCanvasBus::EventResult(clonedMenuElem, canvasEntityId, &UiCanvasBus::Events::CloneElement, pauseMenuElem, nullptr);
  1139. AZ::EntityId clonedMenuId = clonedMenuElem->GetId();
  1140. UiTransform2dBus::Event(
  1141. clonedMenuId, &UiTransform2dBus::Events::SetAnchors, UiTransform2dInterface::Anchors(0.0f, 0.25f, 0.23f, 0.75f), false, false);
  1142. UiImageBus::Event(clonedMenuId, &UiImageBus::Events::SetColor, grey);
  1143. // The clone will copy the action name on the Hide button but not the callback on the
  1144. // Show button, so set that up on the cloned menu
  1145. buttonElem = nullptr;
  1146. UiElementBus::EventResult(buttonElem, clonedMenuId, &UiElementBus::Events::FindDescendantByName, "ShowImage");
  1147. UiButtonBus::Event(buttonElem->GetId(), &UiButtonBus::Events::SetOnClickCallback, setEnabledCallbackFn);
  1148. //! test GUIDs
  1149. LyShine::ElementId id = 0;
  1150. UiElementBus::EventResult(id, buttonElem->GetId(), &UiElementBus::Events::GetElementId);
  1151. AZ::Entity* foundElem = canvas->FindElementById(id);
  1152. AZ_Assert(foundElem == buttonElem, "FindElementById failed");
  1153. //! test find by name
  1154. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByName, "ChangedText");
  1155. AZ_Assert(foundElem == changedTextElem, "FindElementByName failed");
  1156. LyShine::EntityArray foundElements;
  1157. UiCanvasBus::Event(canvasEntityId, &UiCanvasBus::Events::FindElementsByName, "ShowImage", foundElements);
  1158. AZ_Assert(foundElements.size() == 2, "FindElementsByName failed, should find 2 elements");
  1159. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByHierarchicalName, "Menu1/ShowImage");
  1160. AZ_Assert(foundElem == showImageButtonElem, "FindElementByHierarchicalName failed to find Menu1/ShowImage");
  1161. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByHierarchicalName, "/Menu1/ShowImage");
  1162. AZ_Assert(foundElem == showImageButtonElem, "FindElementByHierarchicalName failed to find /Menu1/ShowImage");
  1163. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByHierarchicalName, "Menu1/ShowImage/ButtonText");
  1164. AZ_Assert(foundElem, "FindElementByHierarchicalName failed to find Menu1/ShowImage/ButtonText");
  1165. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByHierarchicalName, "Menu1/ShowImage/ButtonText/");
  1166. AZ_Assert(!foundElem, "FindElementByHierarchicalName succeeded with bad path");
  1167. UiCanvasBus::EventResult(foundElem, canvasEntityId, &UiCanvasBus::Events::FindElementByHierarchicalName, "ShowImage");
  1168. AZ_Assert(!foundElem, "FindElementByHierarchicalName found ShowImage when it should not");
  1169. }
  1170. static void TestCanvasRemove([[maybe_unused]] IConsoleCmdArgs* Cmd)
  1171. {
  1172. if (gEnv->IsEditing())
  1173. {
  1174. return;
  1175. }
  1176. // remove the existing test canvas if it exists
  1177. DestroyTestCanvas();
  1178. }
  1179. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1180. // PUBLIC STATIC MEMBER FUNCTIONS
  1181. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1182. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1183. void LyShineDebug::Initialize()
  1184. {
  1185. #ifndef EXCLUDE_DOCUMENTATION_PURPOSE
  1186. DefineConstIntCVar3("r_DebugUIDraw2dFont", CV_r_DebugUIDraw2dFont, 0, VF_CHEAT,
  1187. "0=off, 1=display various features of the UI font rendering to verify function and to document usage");
  1188. DefineConstIntCVar3("r_DebugUIDraw2dImage", CV_r_DebugUIDraw2dImage, 0, VF_CHEAT,
  1189. "0=off, 1=display various features of the UI image rendering to verify function and to document usage");
  1190. DefineConstIntCVar3("r_DebugUIDraw2dLine", CV_r_DebugUIDraw2dLine, 0, VF_CHEAT,
  1191. "0=off, 1=display various features of the UI line rendering to verify function and to document usage");
  1192. DefineConstIntCVar3("r_DebugUIDraw2dDefer", CV_r_DebugUIDraw2dDefer, 0, VF_CHEAT,
  1193. "0=draws 2D immediately in debug tests, 1=defers calls in debug tests");
  1194. REGISTER_COMMAND("ui_TestCanvasCreate", &TestCanvasCreate, VF_NULL, "");
  1195. REGISTER_COMMAND("ui_TestCanvasRemove", &TestCanvasRemove, VF_NULL, "");
  1196. #endif // EXCLUDE_DOCUMENTATION_PURPOSE
  1197. }
  1198. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1199. void LyShineDebug::Reset()
  1200. {
  1201. // remove the existing test canvas if it exists
  1202. DestroyTestCanvas();
  1203. }
  1204. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1205. void LyShineDebug::RenderDebug()
  1206. {
  1207. #if !defined(_RELEASE)
  1208. #ifndef EXCLUDE_DOCUMENTATION_PURPOSE
  1209. IDraw2d* draw2d = Draw2dHelper::GetDefaultDraw2d();
  1210. if (!draw2d)
  1211. {
  1212. return;
  1213. }
  1214. g_deferDrawsToEndOfFrame = (CV_r_DebugUIDraw2dDefer) ? true : false;
  1215. // Set whether to defer draws or render immediately during scope of this helper
  1216. Draw2dHelper draw2dHelper(g_deferDrawsToEndOfFrame);
  1217. if (CV_r_DebugUIDraw2dFont)
  1218. {
  1219. switch (CV_r_DebugUIDraw2dFont)
  1220. {
  1221. case 1: // test font sizes (default font, effect 0)
  1222. DebugDraw2dFontSizes("default", 0);
  1223. break;
  1224. case 2: // test font sizes (default font, effect 1)
  1225. DebugDraw2dFontSizes("default", 1);
  1226. break;
  1227. case 3: // test font alignment
  1228. DebugDraw2dFontAlignment();
  1229. break;
  1230. case 4: // test font color and opacity
  1231. DebugDraw2dFontColorAndOpacity();
  1232. break;
  1233. }
  1234. }
  1235. if (CV_r_DebugUIDraw2dImage)
  1236. {
  1237. switch (CV_r_DebugUIDraw2dImage)
  1238. {
  1239. case 1: // test image rotation
  1240. DebugDraw2dImageRotations();
  1241. break;
  1242. case 2: // test image color
  1243. DebugDraw2dImageColor();
  1244. break;
  1245. case 3: // test image blend mode
  1246. DebugDraw2dImageBlendMode();
  1247. break;
  1248. case 4: // test image UVs
  1249. DebugDraw2dImageUVs();
  1250. break;
  1251. case 5: // test image pixel rounding
  1252. DebugDraw2dImagePixelRounding();
  1253. break;
  1254. }
  1255. }
  1256. if (CV_r_DebugUIDraw2dLine)
  1257. {
  1258. switch (CV_r_DebugUIDraw2dLine)
  1259. {
  1260. case 1: // test basic draw line
  1261. DebugDraw2dLineBasic();
  1262. break;
  1263. }
  1264. }
  1265. #endif
  1266. #endif
  1267. }