ImGuiSystemComponent.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 <ImGui/ImGuiSystemComponent.h>
  9. #include <ImGui/ImGuiPass.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  12. #include <Atom/RPI.Public/Pass/PassFilter.h>
  13. #include <Atom/RPI.Public/ViewportContext.h>
  14. #include <Atom/RPI.Public/ViewportContextBus.h>
  15. namespace AZ
  16. {
  17. namespace Render
  18. {
  19. void ImGuiSystemComponent::Reflect(AZ::ReflectContext* context)
  20. {
  21. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  22. {
  23. serializeContext->Class<ImGuiSystemComponent, AZ::Component>()
  24. ->Version(0)
  25. ;
  26. }
  27. }
  28. void ImGuiSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  29. {
  30. provided.push_back(AZ_CRC_CE("ImGuiSystemComponent"));
  31. }
  32. void ImGuiSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  33. {
  34. required.push_back(AZ_CRC_CE("RPISystem"));
  35. }
  36. void ImGuiSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatbile)
  37. {
  38. incompatbile.push_back(AZ_CRC_CE("ImGuiSystemComponent"));
  39. }
  40. ImGuiSystemComponent::ImGuiSystemComponent()
  41. {
  42. }
  43. void ImGuiSystemComponent::Activate()
  44. {
  45. ImGuiSystemRequestBus::Handler::BusConnect();
  46. }
  47. void ImGuiSystemComponent::Deactivate()
  48. {
  49. ImGuiSystemRequestBus::Handler::BusDisconnect();
  50. }
  51. void ImGuiSystemComponent::SetGlobalSizeScale(float scale)
  52. {
  53. if (m_sizeScale != scale)
  54. {
  55. m_sizeScale = scale;
  56. ForAllImGuiPasses(
  57. [&]([[maybe_unused]] ImGuiPass* pass)
  58. {
  59. ImGui::GetStyle().ScaleAllSizes(m_sizeScale);
  60. }
  61. );
  62. }
  63. }
  64. void ImGuiSystemComponent::SetGlobalFontScale(float scale)
  65. {
  66. if (m_fontScale != scale)
  67. {
  68. m_fontScale = scale;
  69. ForAllImGuiPasses(
  70. [&]([[maybe_unused]] ImGuiPass* pass)
  71. {
  72. ImGui::GetIO().FontGlobalScale = scale;
  73. }
  74. );
  75. }
  76. }
  77. void ImGuiSystemComponent::HideAllImGuiPasses()
  78. {
  79. ForAllImGuiPasses(
  80. [&](ImGuiPass* pass)
  81. {
  82. pass->SetEnabled(false);
  83. }
  84. );
  85. }
  86. void ImGuiSystemComponent::ShowAllImGuiPasses()
  87. {
  88. ForAllImGuiPasses(
  89. [&](ImGuiPass* pass)
  90. {
  91. pass->SetEnabled(true);
  92. }
  93. );
  94. }
  95. void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func)
  96. {
  97. ImGuiContext* contextToRestore = ImGui::GetCurrentContext();
  98. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<ImGuiPass>();
  99. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  100. {
  101. ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
  102. ImGui::SetCurrentContext(imguiPass->GetContext());
  103. func(imguiPass);
  104. return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  105. });
  106. ImGui::SetCurrentContext(contextToRestore);
  107. }
  108. void ImGuiSystemComponent::PushDefaultImGuiPass(ImGuiPass* imguiPass)
  109. {
  110. ImGuiPass** existingPass = AZStd::find(m_defaultImguiPassStack.begin(), m_defaultImguiPassStack.end(), imguiPass);
  111. if (existingPass != m_defaultImguiPassStack.end())
  112. {
  113. AZ_Assert(false, "This Imgui pass is already registered as a default pass.");
  114. return;
  115. }
  116. m_defaultImguiPassStack.push_back(imguiPass);
  117. }
  118. void ImGuiSystemComponent::RemoveDefaultImGuiPass(ImGuiPass* imguiPass)
  119. {
  120. for (size_t i = 0; i < m_defaultImguiPassStack.size(); ++i)
  121. {
  122. if (imguiPass == m_defaultImguiPassStack.at(i))
  123. {
  124. m_defaultImguiPassStack.erase(m_defaultImguiPassStack.begin() + i);
  125. // If the pass being removed as default is at the top of the active stack, replace it
  126. // with whatever's now on the top of the default pass stack.
  127. if (GetActiveContext() == imguiPass->GetContext())
  128. {
  129. PushActiveContextFromDefaultPass();
  130. }
  131. break;
  132. }
  133. }
  134. // The ImGuiPass will delete its context so we need to remove it from the active list
  135. for (size_t i = 0; i < m_activeContextStack.size(); ++i)
  136. {
  137. if (imguiPass->GetContext() == m_activeContextStack.at(i))
  138. {
  139. m_activeContextStack.erase(m_activeContextStack.begin() + i);
  140. break;
  141. }
  142. }
  143. }
  144. ImGuiPass* ImGuiSystemComponent::GetDefaultImGuiPass()
  145. {
  146. return m_defaultImguiPassStack.size() > 0 ? m_defaultImguiPassStack.back() : nullptr;
  147. }
  148. bool ImGuiSystemComponent::PushActiveContextFromDefaultPass()
  149. {
  150. if (m_defaultImguiPassStack.size() > 0)
  151. {
  152. ImGuiContext* context = m_defaultImguiPassStack.back()->GetContext();
  153. m_activeContextStack.push_back(context);
  154. ImGuiSystemNotificationBus::Broadcast(&ImGuiSystemNotifications::ActiveImGuiContextChanged, context);
  155. return true;
  156. }
  157. return false;
  158. }
  159. bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchyFilter)
  160. {
  161. if (passHierarchyFilter.size() == 0)
  162. {
  163. AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty");
  164. return false;
  165. }
  166. AZStd::vector<ImGuiPass*> foundImGuiPasses;
  167. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter);
  168. RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
  169. {
  170. ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
  171. if (imGuiPass)
  172. {
  173. foundImGuiPasses.push_back(imGuiPass);
  174. }
  175. return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  176. });
  177. if (foundImGuiPasses.size() == 0)
  178. {
  179. AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str());
  180. return false;
  181. }
  182. if (foundImGuiPasses.size() > 1)
  183. {
  184. AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str());
  185. }
  186. ImGuiContext* context = foundImGuiPasses.at(0)->GetContext();
  187. m_activeContextStack.push_back(context);
  188. ImGuiSystemNotificationBus::Broadcast(&ImGuiSystemNotifications::ActiveImGuiContextChanged, context);
  189. return true;
  190. }
  191. bool ImGuiSystemComponent::PopActiveContext()
  192. {
  193. if (m_activeContextStack.size() > 0)
  194. {
  195. m_activeContextStack.pop_back();
  196. ImGuiContext* newContext = GetActiveContext();
  197. ImGuiSystemNotificationBus::Broadcast(&ImGuiSystemNotifications::ActiveImGuiContextChanged, newContext);
  198. return true;
  199. }
  200. AZ_Error("ImGuiSystemComponent", false, "Attempting to pop active ImGui context when there are none on the stack. There must be a Push/Pop mismatch.")
  201. return false;
  202. }
  203. ImGuiContext* ImGuiSystemComponent::GetActiveContext()
  204. {
  205. if (m_activeContextStack.size() > 0)
  206. {
  207. return m_activeContextStack.back();
  208. }
  209. return nullptr;
  210. }
  211. bool ImGuiSystemComponent::RenderImGuiBuffersToCurrentViewport(const ImDrawData& drawData)
  212. {
  213. auto atomViewportRequests = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  214. RPI::ViewportContextPtr viewportContext = atomViewportRequests->GetDefaultViewportContext();
  215. if (viewportContext == nullptr)
  216. {
  217. return false;
  218. }
  219. auto renderPipeline = viewportContext->GetCurrentPipeline();
  220. if (renderPipeline == nullptr)
  221. {
  222. return false;
  223. }
  224. for (auto imGuiPass : m_defaultImguiPassStack)
  225. {
  226. if (imGuiPass->GetRenderPipeline() == renderPipeline.get())
  227. {
  228. imGuiPass->RenderImguiDrawData(drawData);
  229. return true;
  230. }
  231. }
  232. return false;
  233. }
  234. } // namespace RPI
  235. } // namespace AZ