3
0

ImGuiLYAssetExplorer.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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 "ImGuiLYAssetExplorer.h"
  9. #ifdef IMGUI_ENABLED
  10. #include <AzCore/Component/TransformBus.h>
  11. #include <AzFramework/Entity/EntityContext.h>
  12. #include <AzFramework/Entity/EntityContextBus.h>
  13. #include <AzFramework/Entity/GameEntityContextBus.h>
  14. #include <AzCore/std/sort.h>
  15. #include <AzCore/std/string/conversions.h>
  16. #include <IRenderAuxGeom.h>
  17. #include <IConsole.h>
  18. #include "ImGuiColorDefines.h"
  19. namespace ImGui
  20. {
  21. // Colors specific to AssetExplorer ( maybe use common ones in ImGuiColorDefines.h too? )
  22. static const ImVec4 s_lodColor_0 = ImColor(1.0f, 1.0f, 1.0f);
  23. static const ImVec4 s_lodColor_1 = ImColor(0.0f, 0.0f, 1.0f);
  24. static const ImVec4 s_lodColor_2 = ImColor(0.0f, 1.0f, 0.0f);
  25. static const ImVec4 s_lodColor_3 = ImColor(0.0f, 1.0f, 1.0f);
  26. static const ImVec4 s_lodColor_4 = ImColor(1.0f, 0.0f, 0.0f);
  27. static const ImVec4 s_lodColor_5 = ImColor(1.0f, 0.0f, 1.0f);
  28. ImGuiLYAssetExplorer::ImGuiLYAssetExplorer()
  29. : m_enabled(false)
  30. , m_meshDebugEnabled(false)
  31. , m_selectionFilter(false)
  32. , m_anyMousedOverForDraw(false)
  33. , m_enabledMouseOvers(true)
  34. , m_distanceFilter(true)
  35. , m_distanceFilter_near(40.0f)
  36. , m_distanceFilter_far(80.0f)
  37. , m_entityNameFilter(true)
  38. , m_meshNameFilter(true)
  39. , m_lodDebugEnabled(false)
  40. , m_inWorld_drawOriginSphere(true)
  41. , m_inWorld_originSphereRadius(0.1f)
  42. , m_inWorld_drawLabel(true)
  43. , m_inWorld_label_framed(true)
  44. , m_inWorld_label_monoSpace(false)
  45. , m_inWorld_label_textColor(1.0f, 0.65f, 0.0f, 1.0f)
  46. , m_inWorld_labelTextSize(1.5f)
  47. , m_inWorld_drawAABB(true)
  48. , m_inWorld_debugDrawMesh(false)
  49. , m_inWorld_label_entityName(true)
  50. , m_inWorld_label_materialName(false)
  51. , m_inWorld_label_totalLods(true)
  52. , m_inWorld_label_miscLod(false)
  53. {
  54. }
  55. ImGuiLYAssetExplorer::~ImGuiLYAssetExplorer()
  56. {
  57. }
  58. void ImGuiLYAssetExplorer::Initialize()
  59. {
  60. // Connect to EBUSes
  61. ImGuiAssetExplorerRequestBus::Handler::BusConnect();
  62. }
  63. void ImGuiLYAssetExplorer::Shutdown()
  64. {
  65. // Disconnect EBUSes
  66. ImGuiAssetExplorerRequestBus::Handler::BusDisconnect();
  67. }
  68. void ImGuiLYAssetExplorer::ImGuiUpdate()
  69. {
  70. // Manage main window visibility
  71. if (m_enabled)
  72. {
  73. if (ImGui::Begin("Asset Explorer", &m_enabled, ImGuiWindowFlags_MenuBar|ImGuiWindowFlags_HorizontalScrollbar|ImGuiWindowFlags_NoSavedSettings))
  74. {
  75. // Draw the Entire Main Menu Window Area
  76. ImGuiUpdate_DrawMenu();
  77. // Draw Menu Bar
  78. if (ImGui::BeginMenuBar())
  79. {
  80. if (ImGui::BeginMenu("View Options##assetExplorer"))
  81. {
  82. ImGuiUpdate_DrawViewOptions();
  83. ImGui::EndMenu();
  84. }
  85. ImGui::EndMenuBar();
  86. }
  87. }
  88. ImGui::End();
  89. }
  90. }
  91. void ImGuiLYAssetExplorer::ImGuiUpdate_DrawViewOptions()
  92. {
  93. // In-World Drawing Options ( Sphere, AABB, Debug Mesh, etc )
  94. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "In-World Drawing");
  95. ImGui::Separator();
  96. ImGui::Checkbox("Draw Origin Sphere", &m_inWorld_drawOriginSphere);
  97. ImGui::DragFloat("Origin Sphere Radius", &m_inWorld_originSphereRadius, 0.01f, 0.0f, 100.0f);
  98. ImGui::Checkbox("Draw AABB", &m_inWorld_drawAABB);
  99. ImGui::Checkbox("Debug Draw Mesh", &m_inWorld_debugDrawMesh);
  100. // In-World Label Options
  101. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "In-World Label Options");
  102. ImGui::Separator();
  103. ImGui::Checkbox("Draw Label", &m_inWorld_drawLabel);
  104. ImGui::Checkbox("Label - Entity Name", &m_inWorld_label_entityName);
  105. ImGui::Checkbox("Label - Monospace", &m_inWorld_label_monoSpace);
  106. ImGui::Checkbox("Label - Framed", &m_inWorld_label_framed);
  107. ImGui::Checkbox("Label - Material Name", &m_inWorld_label_materialName);
  108. ImGui::Checkbox("Label - Total LODs", &m_inWorld_label_totalLods);
  109. ImGui::Checkbox("Label - Misc LOD data", &m_inWorld_label_miscLod);
  110. ImGui::DragFloat("Label Text Size", &m_inWorld_labelTextSize, 0.01f, 0.0f, 100000.0f);
  111. ImGui::ColorEdit4("Label - Text Color", reinterpret_cast<float*>(&m_inWorld_label_textColor.Value));
  112. }
  113. void ImGuiLYAssetExplorer::MeshInstanceList_CheckMeshFilter()
  114. {
  115. // Iterate through the Mesh Instance list, mark a boolean flag if the mesh name passes the Mesh Name Filter.
  116. for (MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
  117. {
  118. meshInstanceList.m_passesFilter = (meshInstanceList.m_meshPath.find(m_meshNameFilterStr) != AZStd::string::npos);
  119. }
  120. }
  121. void ImGuiLYAssetExplorer::MeshInstanceList_CheckEntityFilter()
  122. {
  123. // Iterate through All Meshes..
  124. for (MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
  125. {
  126. // .. reset this flag to see if any child instances pass the name filter
  127. meshInstanceList.m_childrenPassFilter = false;
  128. // .. Iterate through all Instance of this mesh, mark any that pass the Name Filter
  129. for (auto& meshInstance : meshInstanceList.m_instanceOptionMap)
  130. {
  131. meshInstance.second.m_passesFilter = (meshInstance.second.m_instanceLabel.find(m_entityNameFilterStr) != AZStd::string::npos);
  132. // Or in this child's result to help mark if a single Instance of this Mesh passed the filter.
  133. meshInstanceList.m_childrenPassFilter |= meshInstance.second.m_passesFilter;
  134. }
  135. }
  136. }
  137. void ImGuiLYAssetExplorer::ImGuiUpdate_DrawMenu()
  138. {
  139. // Primary on / off Switch
  140. ImGui::Checkbox("Mesh Debug Enabled", &m_meshDebugEnabled);
  141. ImGui::SameLine();
  142. // Lod Debug Switch, check for changes so we can do things once at change time
  143. bool lodDebug = m_lodDebugEnabled;
  144. ImGui::Checkbox("LOD Debug", &lodDebug);
  145. if (lodDebug != m_lodDebugEnabled)
  146. {
  147. // Save off the new debug flag value
  148. m_lodDebugEnabled = lodDebug;
  149. // Find the CVAR and flick the value
  150. static ICVar* eTexelDensityCVAR = gEnv->pConsole->GetCVar("e_texeldensity");
  151. if (eTexelDensityCVAR)
  152. {
  153. eTexelDensityCVAR->Set(m_lodDebugEnabled ? 2 : 0);
  154. }
  155. }
  156. // If the Lod Debug is Enabled. Draw a small legend that
  157. if (m_lodDebugEnabled)
  158. {
  159. ImGui::BeginChild("lodDebugLegend", ImVec2(0.0f, 57.0f), true);
  160. // Text for legend.
  161. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Lod Color Legend:");
  162. ImGui::SameLine();
  163. ImGui::TextColored(s_lodColor_0, "0 ");
  164. ImGui::SameLine();
  165. ImGui::TextColored(s_lodColor_1, "1 ");
  166. ImGui::SameLine();
  167. ImGui::TextColored(s_lodColor_2, "2 ");
  168. ImGui::SameLine();
  169. ImGui::TextColored(s_lodColor_3, "3 ");
  170. ImGui::SameLine();
  171. ImGui::TextColored(s_lodColor_4, "4 ");
  172. ImGui::SameLine();
  173. ImGui::TextColored(s_lodColor_5, "5 ");
  174. // Small boxes of each color to help with the legend
  175. static float s_boxSize = 21.0f;
  176. ImVec2 graphUpLeft(ImGui::GetWindowPos().x + 127.5f, ImGui::GetWindowPos().y + 26.0f);
  177. ImGui::GetWindowDrawList()->AddRectFilled(
  178. ImVec2(graphUpLeft.x + (0 * s_boxSize), graphUpLeft.y),
  179. ImVec2(graphUpLeft.x + (1 * s_boxSize), graphUpLeft.y + s_boxSize),
  180. ImGui::ColorConvertFloat4ToU32(s_lodColor_0), 2.0f);
  181. ImGui::GetWindowDrawList()->AddRectFilled(
  182. ImVec2(graphUpLeft.x + (1 * s_boxSize), graphUpLeft.y),
  183. ImVec2(graphUpLeft.x + (2 * s_boxSize), graphUpLeft.y + s_boxSize),
  184. ImGui::ColorConvertFloat4ToU32(s_lodColor_1), 2.0f);
  185. ImGui::GetWindowDrawList()->AddRectFilled(
  186. ImVec2(graphUpLeft.x + (2 * s_boxSize), graphUpLeft.y),
  187. ImVec2(graphUpLeft.x + (3 * s_boxSize), graphUpLeft.y + s_boxSize),
  188. ImGui::ColorConvertFloat4ToU32(s_lodColor_2), 2.0f);
  189. ImGui::GetWindowDrawList()->AddRectFilled(
  190. ImVec2(graphUpLeft.x + (3 * s_boxSize), graphUpLeft.y),
  191. ImVec2(graphUpLeft.x + (4 * s_boxSize), graphUpLeft.y + s_boxSize),
  192. ImGui::ColorConvertFloat4ToU32(s_lodColor_3), 2.0f);
  193. ImGui::GetWindowDrawList()->AddRectFilled(
  194. ImVec2(graphUpLeft.x + (4 * s_boxSize), graphUpLeft.y),
  195. ImVec2(graphUpLeft.x + (5 * s_boxSize), graphUpLeft.y + s_boxSize),
  196. ImGui::ColorConvertFloat4ToU32(s_lodColor_4), 2.0f);
  197. ImGui::GetWindowDrawList()->AddRectFilled(
  198. ImVec2(graphUpLeft.x + (5 * s_boxSize), graphUpLeft.y),
  199. ImVec2(graphUpLeft.x + (6 * s_boxSize), graphUpLeft.y + s_boxSize),
  200. ImGui::ColorConvertFloat4ToU32(s_lodColor_5), 2.0f);
  201. ImGui::EndChild();
  202. }
  203. // Filter Options
  204. if (ImGui::CollapsingHeader("Filters", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed))
  205. {
  206. ImGui::Columns(3);
  207. // Draw Column Headers
  208. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Distance Filter");
  209. ImGui::NextColumn();
  210. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Mesh Name Filter");
  211. ImGui::NextColumn();
  212. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Entity Name Filter");
  213. ImGui::NextColumn();
  214. ImGui::Separator();
  215. {
  216. // Distance Filter
  217. ImGui::Checkbox("Enabled##distfilter", &m_distanceFilter);
  218. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Near Distance:");
  219. ImGui::SameLine();
  220. ImGui::DragFloat("##Distance Filter Near", &m_distanceFilter_near, 0.1f, 0.0f, 100000.0f);
  221. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "Far Distance:");
  222. ImGui::SameLine();
  223. ImGui::DragFloat("##Distance Filter Far", &m_distanceFilter_far, 0.1f, 0.0f, 100000.0f);
  224. // We don't really want a far distance that is less than our near distance, so lets check for that and correct here
  225. if (m_distanceFilter_far < m_distanceFilter_near)
  226. {
  227. m_distanceFilter_far = m_distanceFilter_near;
  228. }
  229. }
  230. ImGui::NextColumn();
  231. {
  232. // Mesh Name Filter
  233. ImGui::Checkbox("Enabled##meshNameFilter", &m_meshNameFilter);
  234. static char meshNameCharArray[128] = "";
  235. ImGui::InputText("##meshNameFiltertext", meshNameCharArray, sizeof(meshNameCharArray));
  236. // Save off the string and to_lower it
  237. AZStd::string meshNameStr = meshNameCharArray;
  238. AZStd::to_lower(meshNameStr.begin(), meshNameStr.end());
  239. if (meshNameStr != m_meshNameFilterStr)
  240. {
  241. // Mesh Name String Change Detected! Check meshes for filtration
  242. m_meshNameFilterStr = meshNameStr;
  243. MeshInstanceList_CheckMeshFilter();
  244. }
  245. }
  246. ImGui::NextColumn();
  247. {
  248. // Entity Name Filter
  249. ImGui::Checkbox("Enabled##entityNameFilter", &m_entityNameFilter);
  250. static char entityNameCharArray[128] = "";
  251. ImGui::InputText("##entityNameFiltertext", entityNameCharArray, sizeof(entityNameCharArray));
  252. // Save off the string and to_lower it
  253. AZStd::string entityNameStr = entityNameCharArray;
  254. AZStd::to_lower(entityNameStr.begin(), entityNameStr.end());
  255. if (entityNameStr != m_entityNameFilterStr)
  256. {
  257. // Mesh Name String Change Detected! Check meshes for filtration
  258. m_entityNameFilterStr = entityNameStr;
  259. MeshInstanceList_CheckEntityFilter();
  260. }
  261. }
  262. ImGui::Columns(1);
  263. }
  264. // Draw the Mesh Hierarchy
  265. if (ImGui::CollapsingHeader("Meshes In Scene", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed))
  266. {
  267. if (!m_meshInstanceDisplayList.empty())
  268. {
  269. // Buttons to sort by Mesh Name and Instance Count
  270. ImGui::BeginChild("MeshesTitleBarChild", ImVec2(0.0f, 56.0f), true);
  271. ImGui::Columns(3);
  272. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Sort By:");
  273. if (ImGui::Button("Mesh Name"))
  274. {
  275. // A Static int flag to swap to alternate between sorting ascending/descending.
  276. static bool s_meshNameSortUp = false;
  277. s_meshNameSortUp = !s_meshNameSortUp;
  278. if (s_meshNameSortUp)
  279. {
  280. m_meshInstanceDisplayList.sort([](const MeshInstanceDisplayList& meshList1, const MeshInstanceDisplayList& meshList2)
  281. {
  282. return meshList1.m_meshPath < meshList2.m_meshPath;
  283. });
  284. }
  285. else
  286. {
  287. m_meshInstanceDisplayList.sort([](const MeshInstanceDisplayList& meshList1, const MeshInstanceDisplayList& meshList2)
  288. {
  289. return meshList1.m_meshPath > meshList2.m_meshPath;
  290. });
  291. }
  292. }
  293. ImGui::SameLine();
  294. if (ImGui::Button("Instance Count"))
  295. {
  296. // A Static int flag to swap to alternate between sorting ascending/descending.
  297. static bool s_meshCountSortUp = false;
  298. s_meshCountSortUp = !s_meshCountSortUp;
  299. if (s_meshCountSortUp)
  300. {
  301. m_meshInstanceDisplayList.sort([](const MeshInstanceDisplayList& meshList1, const MeshInstanceDisplayList& meshList2)
  302. {
  303. return meshList1.m_instanceOptionMap.size() < meshList2.m_instanceOptionMap.size();
  304. });
  305. }
  306. else
  307. {
  308. m_meshInstanceDisplayList.sort([](const MeshInstanceDisplayList& meshList1, const MeshInstanceDisplayList& meshList2)
  309. {
  310. return meshList1.m_instanceOptionMap.size() > meshList2.m_instanceOptionMap.size();
  311. });
  312. }
  313. }
  314. ImGui::NextColumn();
  315. // A Small Legend and Hints section for help using this thing
  316. ImGui::BeginChild("MouseHoverLegendChild", ImVec2(250.0f, 30.0f), true);
  317. if (ImGui::IsWindowHovered())
  318. {
  319. ImGui::BeginTooltip();
  320. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Legend:");
  321. if (ImGui::TreeNodeEx("Mesh (Count) - Mesh Path", ImGuiTreeNodeFlags_DefaultOpen))
  322. {
  323. if (ImGui::SmallButton("-*View Instance Btn*-"))
  324. {
  325. // Don't need to do anything here. It is just a sample button!
  326. }
  327. ImGui::SameLine();
  328. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "[*EntityId*] *EntityName*");
  329. ImGui::SameLine();
  330. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "(*World Position XYZ*)");
  331. ImGui::TreePop(); // End Tree
  332. }
  333. ImGui::Separator();
  334. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Tips:");
  335. ImGui::Indent();
  336. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, " * Click to the *View Instance Btn* to Snap the camera to any mesh instance local origin");
  337. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, " * Mouse Over any Meshes Groups or Individual Entities to Temporarily only draw those.");
  338. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, " * Use the Selection Filter to only display Meshes and Entities that are manually selected.");
  339. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, " * Selection Filter overrides other filters.");
  340. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, " * Mesh Selection overrides Entity Selection.");
  341. ImGui::EndTooltip();
  342. }
  343. ImGui::TextColored(ImGui::IsWindowHovered() ? ImGui::Colors::s_NiceLabelColor : ImGui::Colors::s_PlainLabelColor, "Mouse Over For Legend and Tips");
  344. ImGui::EndChild(); // MouseHover Child
  345. ImGui::NextColumn();
  346. // Small area for Mouse Over and Selection Filter options
  347. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Mouse Overs: ");
  348. ImGui::SameLine();
  349. ImGui::Checkbox("##EnableMouseOversCheckbox", &m_enabledMouseOvers);
  350. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Filter Selected:");
  351. ImGui::SameLine();
  352. ImGui::Checkbox("##FilterSelectedCheckbox", &m_selectionFilter);
  353. ImGui::SetColumnOffset(2, ImGui::GetWindowWidth() - 168.0f);
  354. ImGui::Columns(1);
  355. ImGui::EndChild(); // Sort/Legend Child
  356. // The Core Mesh Hierarchy
  357. ImGui::BeginChild("MeshesInSceneContainer", ImVec2(0, 400.0f), true);
  358. // Before we draw all these meshes, lets mark this frame as no Mouse Over being drawn.. if any are drawn, they will set this flag
  359. m_anyMousedOverForDraw = false;
  360. if (m_selectionFilter)
  361. {
  362. ImGui::Columns(2);
  363. }
  364. for (MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
  365. {
  366. // See if we should display the mesh: Check for various filters and if they are enabled, & in their status.
  367. bool displayMesh = true;
  368. if (m_meshNameFilter)
  369. {
  370. displayMesh &= meshInstanceList.m_passesFilter;
  371. }
  372. if (m_entityNameFilter)
  373. {
  374. displayMesh &= meshInstanceList.m_childrenPassFilter;
  375. }
  376. // Set this flag to false, flip it if any children end up doing Mouse Overs
  377. meshInstanceList.m_childMousedOverForDraw = false;
  378. meshInstanceList.m_mousedOverForDraw = false;
  379. // If we should draw the mesh, draw the tree node!
  380. if (displayMesh)
  381. {
  382. if (ImGui::TreeNode(AZStd::string::format("Mesh (%03zu) - %s", meshInstanceList.m_instanceOptionMap.size(), meshInstanceList.m_meshPath.c_str()).c_str()))
  383. {
  384. ImGuiUpdate_DrawMeshMouseOver(meshInstanceList);
  385. if (m_selectionFilter)
  386. {
  387. ImGui::NextColumn();
  388. ImGui::Checkbox(AZStd::string::format("##meshCheckBox%s", meshInstanceList.m_meshPath.c_str()).c_str(), &meshInstanceList.m_selectedForDraw);
  389. ImGuiUpdate_DrawMeshMouseOver(meshInstanceList);
  390. ImGui::NextColumn();
  391. }
  392. // Keep Count of our Mesh instances and loop through them drawing them!
  393. int instanceCount = 0;
  394. for (auto& meshInstance : meshInstanceList.m_instanceOptionMap)
  395. {
  396. // See if we should
  397. bool displayEntity = true;
  398. if (m_entityNameFilter)
  399. {
  400. displayEntity = meshInstance.second.m_passesFilter;
  401. }
  402. if (displayEntity)
  403. {
  404. // Get the Name and World Position of this Entity Instance
  405. AZStd::string entityName;
  406. AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, meshInstance.first);
  407. AZ::Vector3 worldPos = AZ::Vector3::CreateOne();
  408. AZ::TransformBus::EventResult(worldPos, meshInstance.first, &AZ::TransformBus::Events::GetWorldTranslation);
  409. ImGui::BeginGroup();
  410. if (ImGui::SmallButton(AZStd::string::format("-View #%03d-##%s", ++instanceCount, meshInstance.first.ToString().c_str()).c_str()))
  411. {
  412. ImGuiEntityOutlinerNotificationBus::Broadcast(&IImGuiEntityOutlinerNotifications::OnImGuiEntityOutlinerTarget, meshInstance.first);
  413. }
  414. // Build the Label String.
  415. ImGui::SameLine();
  416. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "%s %s", meshInstance.first.ToString().c_str(), entityName.c_str());
  417. ImGui::SameLine();
  418. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "(% .02f, % .02f, % .02f)", (float)worldPos.GetX(), (float)worldPos.GetY(), (float)worldPos.GetZ());
  419. ImGui::EndGroup();
  420. // Check for and Draw Entity Instance Mouse Over
  421. meshInstance.second.m_mousedOverForDraw = false;
  422. ImGuiUpdate_DrawEntityInstanceMouseOver(meshInstanceList, meshInstance.first, entityName, meshInstance.second);
  423. if (m_selectionFilter)
  424. {
  425. ImGui::NextColumn();
  426. ImGui::Checkbox(AZStd::string::format("##entityCheckBox%s", meshInstance.first.ToString().c_str()).c_str(), &meshInstance.second.m_selectedForDraw);
  427. ImGuiUpdate_DrawEntityInstanceMouseOver(meshInstanceList, meshInstance.first, entityName, meshInstance.second);
  428. ImGui::NextColumn();
  429. }
  430. }
  431. }
  432. ImGui::TreePop(); // End Mesh Tree
  433. }
  434. else
  435. {
  436. ImGuiUpdate_DrawMeshMouseOver(meshInstanceList);
  437. if (m_selectionFilter)
  438. {
  439. ImGui::NextColumn();
  440. ImGui::Checkbox(AZStd::string::format("##meshCheckBox%s", meshInstanceList.m_meshPath.c_str()).c_str(), &meshInstanceList.m_selectedForDraw);
  441. ImGuiUpdate_DrawMeshMouseOver(meshInstanceList);
  442. ImGui::NextColumn();
  443. }
  444. }
  445. }
  446. }
  447. if (m_selectionFilter)
  448. {
  449. ImGui::SetColumnOffset(1, ImGui::GetWindowWidth() - 60.0f);
  450. ImGui::Columns(1);
  451. }
  452. ImGui::EndChild(); // End the "Meshes in Scene" Child
  453. }
  454. }
  455. }
  456. // Mesh Mouse Over Helper function
  457. void ImGuiLYAssetExplorer::ImGuiUpdate_DrawMeshMouseOver(MeshInstanceDisplayList& meshDisplayList)
  458. {
  459. if (!m_enabledMouseOvers)
  460. {
  461. return;
  462. }
  463. if (ImGui::IsItemHovered())
  464. {
  465. ImGui::BeginTooltip();
  466. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Mesh: ");
  467. ImGui::SameLine();
  468. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "%s", meshDisplayList.m_meshPath.c_str());
  469. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Instance Count: ");
  470. ImGui::SameLine();
  471. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "%d", (int) meshDisplayList.m_instanceOptionMap.size());
  472. // Mark that any Mouse Over has happened ( changes draw mode )
  473. m_anyMousedOverForDraw = true;
  474. ImGui::EndTooltip();
  475. }
  476. meshDisplayList.m_mousedOverForDraw |= ImGui::IsItemHovered();
  477. }
  478. // Entity Instance Helper Function
  479. void ImGuiLYAssetExplorer::ImGuiUpdate_DrawEntityInstanceMouseOver(MeshInstanceDisplayList& meshDisplayList, AZ::EntityId& entityInstance, AZStd::string& entityName, MeshInstanceOptions& instanceOptions)
  480. {
  481. if (!m_enabledMouseOvers)
  482. {
  483. return;
  484. }
  485. if (ImGui::IsItemHovered())
  486. {
  487. ImGui::BeginTooltip();
  488. AZ::Vector3 worldPos = AZ::Vector3::CreateZero();
  489. AZ::TransformBus::EventResult(worldPos, entityInstance, &AZ::TransformBus::Events::GetWorldTranslation);
  490. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Entity: ");
  491. ImGui::SameLine();
  492. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "%s %s", entityInstance.ToString().c_str(), entityName.c_str());
  493. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "Mesh: ");
  494. ImGui::SameLine();
  495. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "%s", meshDisplayList.m_meshPath.c_str());
  496. ImGui::TextColored(ImGui::Colors::s_NiceLabelColor, "World Position: ");
  497. ImGui::SameLine();
  498. ImGui::TextColored(ImGui::Colors::s_PlainLabelColor, "% .02f , % .02f , % .02f", (float)worldPos.GetX(), (float)worldPos.GetY(), (float)worldPos.GetZ());
  499. // Mark that any Mouse Over has happened ( changes draw mode )
  500. m_anyMousedOverForDraw = true;
  501. // Note that this mesh has a child with a mouse over active
  502. meshDisplayList.m_childMousedOverForDraw = true;
  503. ImGui::EndTooltip();
  504. }
  505. instanceOptions.m_mousedOverForDraw |= ImGui::IsItemHovered();
  506. }
  507. MeshInstanceDisplayList& ImGuiLYAssetExplorer::FindOrCreateMeshInstanceList(const char* meshName)
  508. {
  509. // Walk the list and see if an entry for this mesh exists already. If we find one, return it!
  510. for (MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
  511. {
  512. if (meshInstanceList.m_meshPath == meshName)
  513. {
  514. return meshInstanceList;
  515. }
  516. }
  517. // Not found, so create a new entry..
  518. MeshInstanceDisplayList meshList;
  519. meshList.m_meshPath = meshName;
  520. meshList.m_passesFilter = true;
  521. meshList.m_childrenPassFilter = true;
  522. meshList.m_selectedForDraw = false;
  523. meshList.m_mousedOverForDraw = false;
  524. meshList.m_childMousedOverForDraw = false;
  525. // push it to the end of the list, and then return that last entry
  526. m_meshInstanceDisplayList.push_back(meshList);
  527. return m_meshInstanceDisplayList.back();
  528. }
  529. } // namespace ImGui
  530. #endif // IMGUI_ENABLED