UiCanvas.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Ui/UiCanvas.h>
  6. #include <AnKi/Ui/UiManager.h>
  7. #include <AnKi/Resource/ResourceManager.h>
  8. #include <AnKi/GpuMemory/RebarTransientMemoryPool.h>
  9. #include <AnKi/Window/Input.h>
  10. #include <AnKi/Window/NativeWindow.h>
  11. #include <AnKi/Gr/Sampler.h>
  12. #include <AnKi/Gr/GrManager.h>
  13. #include <AnKi/Gr/CommandBuffer.h>
  14. #include <AnKi/Resource/GenericResource.h>
  15. namespace anki {
  16. static void setColorStyleAdia()
  17. {
  18. ImGuiStyle& style = ImGui::GetStyle();
  19. ImVec4* colors = style.Colors;
  20. // Base Colors
  21. const Vec4 bgColor = Vec4(0.10f, 0.105f, 0.11f, 1.00f);
  22. const Vec4 lightBgColor = Vec4(0.15f, 0.16f, 0.17f, 1.00f);
  23. const Vec4 panelColor = Vec4(0.17f, 0.18f, 0.19f, 1.00f);
  24. const Vec4 panelHoverColor = Vec4(0.20f, 0.22f, 0.24f, 1.00f);
  25. const Vec4 panelActiveColor = Vec4(0.23f, 0.26f, 0.29f, 1.00f);
  26. const Vec4 textColor = Vec4(0.86f, 0.87f, 0.88f, 1.00f);
  27. const Vec4 textDisabledColor = Vec4(0.50f, 0.50f, 0.50f, 1.00f);
  28. const Vec4 borderColor = Vec4(0.14f, 0.16f, 0.18f, 1.00f);
  29. const Vec4 blueColor = Vec4(0.26f, 0.59f, 0.98f, 1.00f);
  30. // Main menu
  31. colors[ImGuiCol_MenuBarBg] = bgColor;
  32. // Text
  33. colors[ImGuiCol_Text] = textColor;
  34. colors[ImGuiCol_TextDisabled] = textDisabledColor;
  35. // Windows
  36. colors[ImGuiCol_WindowBg] = bgColor;
  37. colors[ImGuiCol_ChildBg] = bgColor;
  38. colors[ImGuiCol_PopupBg] = bgColor;
  39. colors[ImGuiCol_Border] = borderColor;
  40. colors[ImGuiCol_BorderShadow] = borderColor;
  41. // Headers
  42. colors[ImGuiCol_Header] = blueColor;
  43. colors[ImGuiCol_HeaderHovered] = blueColor;
  44. colors[ImGuiCol_HeaderActive] = blueColor;
  45. // Buttons
  46. colors[ImGuiCol_Button] = panelColor;
  47. colors[ImGuiCol_ButtonHovered] = panelHoverColor;
  48. colors[ImGuiCol_ButtonActive] = panelActiveColor;
  49. // Frame BG
  50. colors[ImGuiCol_FrameBg] = lightBgColor;
  51. colors[ImGuiCol_FrameBgHovered] = panelHoverColor;
  52. colors[ImGuiCol_FrameBgActive] = panelActiveColor;
  53. // Tabs
  54. colors[ImGuiCol_Tab] = panelColor;
  55. colors[ImGuiCol_TabHovered] = panelHoverColor;
  56. colors[ImGuiCol_TabSelected] = panelActiveColor;
  57. colors[ImGuiCol_TabDimmed] = panelColor;
  58. colors[ImGuiCol_TabDimmedSelected] = panelHoverColor;
  59. // Title
  60. colors[ImGuiCol_TitleBg] = bgColor;
  61. colors[ImGuiCol_TitleBgActive] = bgColor;
  62. colors[ImGuiCol_TitleBgCollapsed] = bgColor;
  63. // Scrollbar
  64. colors[ImGuiCol_ScrollbarBg] = bgColor;
  65. colors[ImGuiCol_ScrollbarGrab] = panelColor;
  66. colors[ImGuiCol_ScrollbarGrabHovered] = panelHoverColor;
  67. colors[ImGuiCol_ScrollbarGrabActive] = panelActiveColor;
  68. // Checkmark
  69. colors[ImGuiCol_CheckMark] = blueColor;
  70. // Slider
  71. colors[ImGuiCol_SliderGrab] = blueColor;
  72. colors[ImGuiCol_SliderGrabActive] = blueColor;
  73. // Resize Grip
  74. colors[ImGuiCol_ResizeGrip] = panelColor;
  75. colors[ImGuiCol_ResizeGripHovered] = panelHoverColor;
  76. colors[ImGuiCol_ResizeGripActive] = panelActiveColor;
  77. // Separator
  78. colors[ImGuiCol_Separator] = borderColor;
  79. colors[ImGuiCol_SeparatorHovered] = panelHoverColor;
  80. colors[ImGuiCol_SeparatorActive] = panelActiveColor;
  81. // Plot
  82. colors[ImGuiCol_PlotLines] = textColor;
  83. colors[ImGuiCol_PlotLinesHovered] = panelActiveColor;
  84. colors[ImGuiCol_PlotHistogram] = textColor;
  85. colors[ImGuiCol_PlotHistogramHovered] = panelActiveColor;
  86. // Text Selected BG
  87. colors[ImGuiCol_TextSelectedBg] = blueColor;
  88. // Modal Window Dim Bg
  89. colors[ImGuiCol_ModalWindowDimBg] = Vec4(0.10f, 0.105f, 0.11f, 0.5f);
  90. // Tables
  91. colors[ImGuiCol_TableHeaderBg] = panelColor;
  92. colors[ImGuiCol_TableBorderStrong] = borderColor;
  93. colors[ImGuiCol_TableBorderLight] = borderColor;
  94. colors[ImGuiCol_TableRowBg] = bgColor;
  95. colors[ImGuiCol_TableRowBgAlt] = lightBgColor;
  96. // Styles
  97. style.FrameBorderSize = 1.0f;
  98. style.FrameRounding = 2.0f;
  99. style.WindowBorderSize = 1.0f;
  100. style.PopupBorderSize = 1.0f;
  101. style.ScrollbarSize = 12.0f;
  102. style.ScrollbarRounding = 2.0f;
  103. style.GrabMinSize = 7.0f;
  104. style.GrabRounding = 2.0f;
  105. style.TabBorderSize = 1.0f;
  106. style.TabRounding = 2.0f;
  107. // Reduced Padding and Spacing
  108. style.WindowPadding = Vec2(5.0f, 5.0f);
  109. style.FramePadding = Vec2(4.0f, 3.0f);
  110. style.ItemSpacing = Vec2(6.0f, 4.0f);
  111. style.ItemInnerSpacing = Vec2(4.0f, 4.0f);
  112. }
  113. [[maybe_unused]] static void setStypeHalfLife()
  114. {
  115. ImVec4* colors = ImGui::GetStyle().Colors;
  116. colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
  117. colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
  118. colors[ImGuiCol_WindowBg] = ImVec4(0.29f, 0.34f, 0.26f, 1.00f);
  119. colors[ImGuiCol_ChildBg] = ImVec4(0.29f, 0.34f, 0.26f, 1.00f);
  120. colors[ImGuiCol_PopupBg] = ImVec4(0.24f, 0.27f, 0.20f, 1.00f);
  121. colors[ImGuiCol_Border] = ImVec4(0.54f, 0.57f, 0.51f, 0.50f);
  122. colors[ImGuiCol_BorderShadow] = ImVec4(0.14f, 0.16f, 0.11f, 0.52f);
  123. colors[ImGuiCol_FrameBg] = ImVec4(0.24f, 0.27f, 0.20f, 1.00f);
  124. colors[ImGuiCol_FrameBgHovered] = ImVec4(0.27f, 0.30f, 0.23f, 1.00f);
  125. colors[ImGuiCol_FrameBgActive] = ImVec4(0.30f, 0.34f, 0.26f, 1.00f);
  126. colors[ImGuiCol_TitleBg] = ImVec4(0.24f, 0.27f, 0.20f, 1.00f);
  127. colors[ImGuiCol_TitleBgActive] = ImVec4(0.29f, 0.34f, 0.26f, 1.00f);
  128. colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
  129. colors[ImGuiCol_MenuBarBg] = ImVec4(0.24f, 0.27f, 0.20f, 1.00f);
  130. colors[ImGuiCol_ScrollbarBg] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  131. colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.28f, 0.32f, 0.24f, 1.00f);
  132. colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.25f, 0.30f, 0.22f, 1.00f);
  133. colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.23f, 0.27f, 0.21f, 1.00f);
  134. colors[ImGuiCol_CheckMark] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  135. colors[ImGuiCol_SliderGrab] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  136. colors[ImGuiCol_SliderGrabActive] = ImVec4(0.54f, 0.57f, 0.51f, 0.50f);
  137. colors[ImGuiCol_Button] = ImVec4(0.29f, 0.34f, 0.26f, 0.40f);
  138. colors[ImGuiCol_ButtonHovered] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  139. colors[ImGuiCol_ButtonActive] = ImVec4(0.54f, 0.57f, 0.51f, 0.50f);
  140. colors[ImGuiCol_Header] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  141. colors[ImGuiCol_HeaderHovered] = ImVec4(0.35f, 0.42f, 0.31f, 0.6f);
  142. colors[ImGuiCol_HeaderActive] = ImVec4(0.54f, 0.57f, 0.51f, 0.50f);
  143. colors[ImGuiCol_Separator] = ImVec4(0.14f, 0.16f, 0.11f, 1.00f);
  144. colors[ImGuiCol_SeparatorHovered] = ImVec4(0.54f, 0.57f, 0.51f, 1.00f);
  145. colors[ImGuiCol_SeparatorActive] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  146. colors[ImGuiCol_ResizeGrip] = ImVec4(0.19f, 0.23f, 0.18f, 0.00f); // grip invis
  147. colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.54f, 0.57f, 0.51f, 1.00f);
  148. colors[ImGuiCol_ResizeGripActive] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  149. colors[ImGuiCol_Tab] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  150. colors[ImGuiCol_TabHovered] = ImVec4(0.54f, 0.57f, 0.51f, 0.78f);
  151. colors[ImGuiCol_TabSelected] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  152. colors[ImGuiCol_TabDimmed] = ImVec4(0.24f, 0.27f, 0.20f, 1.00f);
  153. colors[ImGuiCol_TabDimmedSelected] = ImVec4(0.35f, 0.42f, 0.31f, 1.00f);
  154. colors[ImGuiCol_DockingPreview] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  155. colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
  156. colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
  157. colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  158. colors[ImGuiCol_PlotHistogram] = ImVec4(1.00f, 0.78f, 0.28f, 1.00f);
  159. colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
  160. colors[ImGuiCol_TextSelectedBg] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  161. colors[ImGuiCol_DragDropTarget] = ImVec4(0.73f, 0.67f, 0.24f, 1.00f);
  162. colors[ImGuiCol_NavCursor] = ImVec4(0.59f, 0.54f, 0.18f, 1.00f);
  163. colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
  164. colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
  165. colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
  166. ImGuiStyle& style = ImGui::GetStyle();
  167. style.FrameBorderSize = 1.0f;
  168. style.WindowRounding = 0.0f;
  169. style.ChildRounding = 0.0f;
  170. style.FrameRounding = 0.0f;
  171. style.PopupRounding = 0.0f;
  172. style.ScrollbarRounding = 0.0f;
  173. style.GrabRounding = 0.0f;
  174. style.TabRounding = 0.0f;
  175. }
  176. static MouseCursor imguiCursorToAnki(ImGuiMouseCursor imguiCursor)
  177. {
  178. #define ANKI_HANDLE(ak, imgui) \
  179. case imgui: \
  180. akCursor = MouseCursor::ak; \
  181. break;
  182. MouseCursor akCursor = MouseCursor::kCount;
  183. switch(imguiCursor)
  184. {
  185. ANKI_HANDLE(kArrow, ImGuiMouseCursor_Arrow)
  186. ANKI_HANDLE(kTextInput, ImGuiMouseCursor_TextInput)
  187. ANKI_HANDLE(kResizeAll, ImGuiMouseCursor_ResizeAll)
  188. ANKI_HANDLE(kResizeNS, ImGuiMouseCursor_ResizeNS)
  189. ANKI_HANDLE(kResizeEW, ImGuiMouseCursor_ResizeEW)
  190. ANKI_HANDLE(kResizeNESW, ImGuiMouseCursor_ResizeNESW)
  191. ANKI_HANDLE(kResizeNWSE, ImGuiMouseCursor_ResizeNWSE)
  192. ANKI_HANDLE(kHand, ImGuiMouseCursor_Hand)
  193. ANKI_HANDLE(kWait, ImGuiMouseCursor_Wait)
  194. ANKI_HANDLE(kProgress, ImGuiMouseCursor_Progress)
  195. ANKI_HANDLE(kNotAllowed, ImGuiMouseCursor_NotAllowed)
  196. default:
  197. break;
  198. }
  199. #undef ANKI_HANDLE
  200. ANKI_ASSERT(akCursor != MouseCursor::kCount);
  201. return akCursor;
  202. }
  203. UiCanvas::~UiCanvas()
  204. {
  205. if(m_imCtx)
  206. {
  207. ImGui::SetCurrentContext(m_imCtx);
  208. for(ImTextureData* tex : ImGui::GetPlatformIO().Textures)
  209. {
  210. ImTextureID it = tex->GetTexID();
  211. ANKI_ASSERT(it.m_textureIsRefcounted);
  212. TexturePtr pTex(it.m_texture);
  213. it.m_texture->release();
  214. }
  215. ImGui::SetCurrentContext(nullptr);
  216. ImGui::DestroyContext(m_imCtx);
  217. }
  218. }
  219. Error UiCanvas::init(UVec2 size)
  220. {
  221. resize(size);
  222. // Create program
  223. ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/Ui.ankiprogbin", m_prog));
  224. for(U32 i = 0; i < kShaderCount; ++i)
  225. {
  226. const ShaderProgramResourceVariant* variant;
  227. ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
  228. variantInitInfo.addMutation("TEXTURE_TYPE", i);
  229. m_prog->getOrCreateVariant(variantInitInfo, variant);
  230. m_grProgs[i].reset(&variant->getProgram());
  231. }
  232. // Sampler
  233. SamplerInitInfo samplerInit("UiCanvas");
  234. samplerInit.m_minMagFilter = SamplingFilter::kLinear;
  235. samplerInit.m_mipmapFilter = SamplingFilter::kLinear;
  236. samplerInit.m_addressing = SamplingAddressing::kRepeat;
  237. m_linearLinearRepeatSampler = GrManager::getSingleton().newSampler(samplerInit);
  238. samplerInit.m_minMagFilter = SamplingFilter::kNearest;
  239. samplerInit.m_mipmapFilter = SamplingFilter::kNearest;
  240. m_nearestNearestRepeatSampler = GrManager::getSingleton().newSampler(samplerInit);
  241. // Create the context
  242. m_imCtx = ImGui::CreateContext(nullptr);
  243. ImGui::SetCurrentContext(m_imCtx);
  244. ImGuiIO& io = ImGui::GetIO();
  245. io.IniFilename = nullptr;
  246. io.LogFilename = nullptr;
  247. io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_HasMouseCursors;
  248. io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
  249. // ImGui::StyleColorsLight();
  250. setColorStyleAdia();
  251. // setStypeHalfLife();
  252. m_defaultFont = addFont("EngineAssets/UbuntuRegular.ttf");
  253. ImGui::SetCurrentContext(nullptr);
  254. return Error::kNone;
  255. }
  256. ImFont* UiCanvas::addFont(CString fname)
  257. {
  258. Array<CString, 1> fnames = {fname};
  259. return addFonts(fnames);
  260. }
  261. ImFont* UiCanvas::addFonts(ConstWeakArray<CString> fnames)
  262. {
  263. ANKI_ASSERT(fnames.getSize() > 0);
  264. ANKI_ASSERT(GImGui);
  265. ImFont* font = nullptr;
  266. U64 hash = fnames[0].computeHash();
  267. for(U32 i = 1; i < fnames.getSize(); ++i)
  268. {
  269. hash = appendHash(fnames[i].getBegin(), fnames[i].getLength(), hash);
  270. }
  271. auto it = m_fontCache.find(hash);
  272. if(it != m_fontCache.getEnd())
  273. {
  274. font = (*it).m_font;
  275. }
  276. else
  277. {
  278. UiDynamicArray<GenericResourcePtr> resources;
  279. resources.resize(fnames.getSize());
  280. for(U32 i = 0; i < fnames.getSize(); ++i)
  281. {
  282. if(ResourceManager::getSingleton().loadResource(fnames[i], resources[i]))
  283. {
  284. ANKI_UI_LOGE("Failed to add font. Will use the default one");
  285. return m_defaultFont;
  286. }
  287. }
  288. for(U32 i = 0; i < fnames.getSize(); ++i)
  289. {
  290. ConstWeakArray<U8> data = resources[i]->getData();
  291. const F32 someFontSize = 13.0f; // Doesn't matter
  292. ImFontConfig cfg;
  293. cfg.FontDataOwnedByAtlas = false;
  294. cfg.MergeMode = (i > 0);
  295. ImFont* newFont = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(const_cast<U8*>(data.getBegin()), data.getSize(), someFontSize, &cfg);
  296. ANKI_ASSERT(font == nullptr || newFont == font);
  297. font = newFont;
  298. ANKI_ASSERT(font);
  299. }
  300. const FontCacheEntry entry = {font, std::move(resources)};
  301. m_fontCache.emplace(hash, entry);
  302. }
  303. return font;
  304. }
  305. void UiCanvas::handleInput()
  306. {
  307. Input& in = Input::getSingleton();
  308. // Begin
  309. ImGui::SetCurrentContext(m_imCtx);
  310. ImGuiIO& io = ImGui::GetIO();
  311. // Handle mouse
  312. Array<U32, 4> viewport = {0, 0, m_size.x, m_size.y};
  313. Vec2 mousePosf = in.getMousePositionNdc() / 2.0f + 0.5f;
  314. mousePosf.y = 1.0f - mousePosf.y;
  315. const UVec2 mousePos(U32(mousePosf.x * F32(viewport[2])), U32(mousePosf.y * F32(viewport[3])));
  316. io.MousePos.x = F32(mousePos.x);
  317. io.MousePos.y = F32(mousePos.y);
  318. io.MouseClicked[0] = in.getMouseButton(MouseButton::kLeft) == 1;
  319. io.MouseDown[0] = in.getMouseButton(MouseButton::kLeft) > 0;
  320. if(in.getMouseButton(MouseButton::kScrollUp) > 0)
  321. {
  322. io.AddMouseWheelEvent(0.0f, 1.0f);
  323. }
  324. else if(in.getMouseButton(MouseButton::kScrollDown) > 0)
  325. {
  326. io.AddMouseWheelEvent(0.0f, -1.0f);
  327. }
  328. // io.KeyCtrl = (in.getKey(KeyCode::kLeftCtrl) || in.getKey(KeyCode::kRightCtrl));
  329. // Handle keyboard
  330. #define ANKI_HANDLE(ak, imgui) \
  331. if(in.getKey(ak) > 0) \
  332. { \
  333. io.AddKeyEvent(imgui, true); \
  334. } \
  335. else if(in.getKey(ak) < 0) \
  336. { \
  337. io.AddKeyEvent(imgui, false); \
  338. }
  339. ANKI_HANDLE(KeyCode::kTab, ImGuiKey_Tab)
  340. ANKI_HANDLE(KeyCode::kLeft, ImGuiKey_LeftArrow)
  341. ANKI_HANDLE(KeyCode::kRight, ImGuiKey_RightArrow)
  342. ANKI_HANDLE(KeyCode::kUp, ImGuiKey_UpArrow)
  343. ANKI_HANDLE(KeyCode::kDown, ImGuiKey_DownArrow)
  344. ANKI_HANDLE(KeyCode::kPageUp, ImGuiKey_PageUp)
  345. ANKI_HANDLE(KeyCode::kPageDown, ImGuiKey_PageDown)
  346. ANKI_HANDLE(KeyCode::kHome, ImGuiKey_Home)
  347. ANKI_HANDLE(KeyCode::kEnd, ImGuiKey_End)
  348. ANKI_HANDLE(KeyCode::kInsert, ImGuiKey_Insert)
  349. ANKI_HANDLE(KeyCode::kDelete, ImGuiKey_Delete)
  350. ANKI_HANDLE(KeyCode::kBackspace, ImGuiKey_Backspace)
  351. ANKI_HANDLE(KeyCode::kSpace, ImGuiKey_Space)
  352. ANKI_HANDLE(KeyCode::kReturn, ImGuiKey_Enter)
  353. // ANKI_HANDLE(KeyCode::RETURN2, ImGuiKey_Enter)
  354. ANKI_HANDLE(KeyCode::kEscape, ImGuiKey_Escape)
  355. ANKI_HANDLE(KeyCode::kA, ImGuiKey_A)
  356. ANKI_HANDLE(KeyCode::kC, ImGuiKey_C)
  357. ANKI_HANDLE(KeyCode::kV, ImGuiKey_V)
  358. ANKI_HANDLE(KeyCode::kX, ImGuiKey_X)
  359. ANKI_HANDLE(KeyCode::kY, ImGuiKey_Y)
  360. ANKI_HANDLE(KeyCode::kZ, ImGuiKey_Z)
  361. ANKI_HANDLE(KeyCode::kLeftCtrl, ImGuiKey_LeftCtrl)
  362. ANKI_HANDLE(KeyCode::kRightCtrl, ImGuiKey_RightCtrl)
  363. #undef ANKI_HANDLE
  364. #define ANKI_HANDLE(ak, imgui) \
  365. if(in.getKey(ak) > 0) \
  366. { \
  367. io.AddKeyEvent(imgui, true); \
  368. } \
  369. else if(in.getKey(ak) < 0) \
  370. { \
  371. io.AddKeyEvent(imgui, false); \
  372. }
  373. ANKI_HANDLE(KeyCode::kLeftCtrl, ImGuiMod_Ctrl)
  374. ANKI_HANDLE(KeyCode::kLeftShift, ImGuiMod_Shift)
  375. ANKI_HANDLE(KeyCode::kLeftAlt, ImGuiMod_Alt);
  376. ANKI_HANDLE(KeyCode::kReturn, ImGuiMod_Super);
  377. #undef ANKI_HANDLE
  378. io.AddInputCharactersUTF8(in.getTextInput().cstr());
  379. const ImGuiMouseCursor imguiCursor = ImGui::GetMouseCursor();
  380. if(io.MouseDrawCursor || imguiCursor == ImGuiMouseCursor_None)
  381. {
  382. // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
  383. in.hideCursor(true);
  384. }
  385. else
  386. {
  387. // Show OS mouse cursor
  388. in.hideCursor(false);
  389. in.setMouseCursor(imguiCursorToAnki(imguiCursor));
  390. }
  391. // End
  392. ImGui::SetCurrentContext(nullptr);
  393. }
  394. void UiCanvas::beginBuilding()
  395. {
  396. ImGui::SetCurrentContext(m_imCtx);
  397. ImGuiIO& io = ImGui::GetIO();
  398. io.DeltaTime = 1.0f / 60.0f;
  399. io.DisplaySize = Vec2(m_size);
  400. ImGui::NewFrame();
  401. }
  402. void UiCanvas::endBuilding()
  403. {
  404. ImGui::Render();
  405. // Create the new textures
  406. m_texturesPendingUpload.destroy();
  407. ImDrawData& drawData = *ImGui::GetDrawData();
  408. if(drawData.Textures != nullptr)
  409. {
  410. for(ImTextureData* tex : *drawData.Textures)
  411. {
  412. const ImTextureStatus status = tex->Status;
  413. if(status == ImTextureStatus_OK)
  414. {
  415. continue;
  416. }
  417. if(status == ImTextureStatus_WantCreate)
  418. {
  419. TextureInitInfo init("ImGui requested");
  420. init.m_width = tex->Width;
  421. init.m_height = tex->Height;
  422. init.m_format = Format::kR8G8B8A8_Unorm;
  423. init.m_usage = TextureUsageBit::kSrvPixel | TextureUsageBit::kCopyDestination;
  424. TexturePtr aktex = GrManager::getSingleton().newTexture(init);
  425. ImTextureID id;
  426. id.m_texture = aktex.get();
  427. id.m_texture->retain();
  428. id.m_textureIsRefcounted = true;
  429. tex->SetTexID(id);
  430. tex->SetStatus(ImTextureStatus_OK);
  431. }
  432. if(status == ImTextureStatus_WantCreate || status == ImTextureStatus_WantUpdates)
  433. {
  434. const Bool isNew = status == ImTextureStatus_WantCreate;
  435. ImTextureID id = tex->GetTexID();
  436. UploadRequest req;
  437. req.m_rect.m_offsetX = isNew ? 0 : tex->UpdateRect.x;
  438. req.m_rect.m_offsetY = isNew ? 0 : tex->UpdateRect.y;
  439. req.m_rect.m_width = isNew ? tex->Width : tex->UpdateRect.w;
  440. req.m_rect.m_height = isNew ? tex->Height : tex->UpdateRect.h;
  441. req.m_texture = id.m_texture;
  442. req.m_isNew = isNew;
  443. const U32 uploadPitch = req.m_rect.m_width * U32(tex->BytesPerPixel);
  444. const U32 copyBufferSize = req.m_rect.m_height * uploadPitch;
  445. req.m_data.resize(copyBufferSize);
  446. for(U32 y = 0; y < req.m_rect.m_height; y++)
  447. {
  448. memcpy(&req.m_data[uploadPitch * y], tex->GetPixelsAt(req.m_rect.m_offsetX, req.m_rect.m_offsetY + y), uploadPitch);
  449. }
  450. m_texturesPendingUpload.emplaceBack(std::move(req));
  451. tex->SetStatus(ImTextureStatus_OK);
  452. }
  453. else if(status == ImTextureStatus_WantDestroy
  454. && tex->UnusedFrames >= I32(kMaxFramesInFlight + 2)) // kMaxFramesInFlight + 2 to be 100% sure
  455. {
  456. ImTextureID id = tex->GetTexID();
  457. ANKI_ASSERT(id.m_textureIsRefcounted);
  458. TexturePtr pTex(id.m_texture);
  459. id.m_texture->release();
  460. tex->SetTexID(ImTextureID(ImTextureID_Invalid));
  461. tex->SetStatus(ImTextureStatus_Destroyed);
  462. }
  463. }
  464. }
  465. ImGui::SetCurrentContext(nullptr);
  466. }
  467. void UiCanvas::appendNonGraphicsCommands(CommandBuffer& cmdb) const
  468. {
  469. for(const UploadRequest& req : m_texturesPendingUpload)
  470. {
  471. WeakArray<U8> mappedMem;
  472. const BufferView copyBuffer = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(req.m_data.getSize(), mappedMem);
  473. memcpy(mappedMem.getBegin(), req.m_data.getBegin(), req.m_data.getSizeInBytes());
  474. cmdb.copyBufferToTexture(copyBuffer, TextureView(req.m_texture, TextureSubresourceDesc::all()), req.m_rect);
  475. }
  476. }
  477. void UiCanvas::appendGraphicsCommands(CommandBuffer& cmdb) const
  478. {
  479. ImGui::SetCurrentContext(m_imCtx);
  480. const ImDrawData& drawData = *ImGui::GetDrawData();
  481. // Allocate index and vertex buffers
  482. BufferView vertsToken, indicesToken;
  483. {
  484. if(drawData.TotalVtxCount == 0 || drawData.TotalIdxCount == 0)
  485. {
  486. return;
  487. }
  488. ImDrawVert* verts;
  489. vertsToken = RebarTransientMemoryPool::getSingleton().allocate(drawData.TotalVtxCount * sizeof(ImDrawVert), sizeof(F32), verts);
  490. ImDrawIdx* indices;
  491. indicesToken = RebarTransientMemoryPool::getSingleton().allocate(drawData.TotalIdxCount * sizeof(ImDrawIdx), sizeof(ImDrawIdx), indices);
  492. for(I32 n = 0; n < drawData.CmdListsCount; ++n)
  493. {
  494. const ImDrawList& cmdList = *drawData.CmdLists[n];
  495. memcpy(verts, cmdList.VtxBuffer.Data, cmdList.VtxBuffer.Size * sizeof(ImDrawVert));
  496. memcpy(indices, cmdList.IdxBuffer.Data, cmdList.IdxBuffer.Size * sizeof(ImDrawIdx));
  497. verts += cmdList.VtxBuffer.Size;
  498. indices += cmdList.IdxBuffer.Size;
  499. }
  500. }
  501. cmdb.setBlendFactors(0, BlendFactor::kSrcAlpha, BlendFactor::kOneMinusSrcAlpha);
  502. cmdb.setCullMode(FaceSelectionBit::kNone);
  503. const F32 fbWidth = drawData.DisplaySize.x * drawData.FramebufferScale.x;
  504. const F32 fbHeight = drawData.DisplaySize.y * drawData.FramebufferScale.y;
  505. cmdb.setViewport(0, 0, U32(fbWidth), U32(fbHeight));
  506. cmdb.bindVertexBuffer(0, vertsToken, sizeof(ImDrawVert));
  507. cmdb.setVertexAttribute(VertexAttributeSemantic::kPosition, 0, Format::kR32G32_Sfloat, 0);
  508. cmdb.setVertexAttribute(VertexAttributeSemantic::kColor, 0, Format::kR8G8B8A8_Unorm, sizeof(Vec2) * 2);
  509. cmdb.setVertexAttribute(VertexAttributeSemantic::kTexCoord, 0, Format::kR32G32_Sfloat, sizeof(Vec2));
  510. cmdb.bindIndexBuffer(indicesToken, IndexType::kU16);
  511. // Will project scissor/clipping rectangles into framebuffer space
  512. const Vec2 clipOff = drawData.DisplayPos; // (0,0) unless using multi-viewports
  513. const Vec2 clipScale = drawData.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
  514. // Render
  515. U32 vertOffset = 0;
  516. U32 idxOffset = 0;
  517. for(I32 n = 0; n < drawData.CmdListsCount; n++)
  518. {
  519. const ImDrawList& cmdList = *drawData.CmdLists[n];
  520. for(I32 i = 0; i < cmdList.CmdBuffer.Size; i++)
  521. {
  522. const ImDrawCmd& pcmd = cmdList.CmdBuffer[i];
  523. if(pcmd.UserCallback)
  524. {
  525. // User callback (registered via ImDrawList::AddCallback), ignore
  526. ANKI_UI_LOGW("Got user callback. Will ignore");
  527. }
  528. else
  529. {
  530. // Project scissor/clipping rectangles into framebuffer space
  531. Vec4 clipRect;
  532. clipRect.x = (pcmd.ClipRect.x - clipOff.x) * clipScale.x;
  533. clipRect.y = (pcmd.ClipRect.y - clipOff.y) * clipScale.y;
  534. clipRect.z = (pcmd.ClipRect.z - clipOff.x) * clipScale.x;
  535. clipRect.w = (pcmd.ClipRect.w - clipOff.y) * clipScale.y;
  536. if(clipRect.x < fbWidth && clipRect.y < fbHeight && clipRect.z >= 0.0f && clipRect.w >= 0.0f)
  537. {
  538. // Negative offsets are illegal for vkCmdSetScissor
  539. if(clipRect.x < 0.0f)
  540. {
  541. clipRect.x = 0.0f;
  542. }
  543. if(clipRect.y < 0.0f)
  544. {
  545. clipRect.y = 0.0f;
  546. }
  547. // Apply scissor/clipping rectangle
  548. cmdb.setScissor(U32(clipRect.x), U32(clipRect.y), U32(clipRect.z - clipRect.x), U32(clipRect.w - clipRect.y));
  549. const ImTextureID texid = pcmd.GetTexID();
  550. const Bool hasTexture = texid.m_texture != nullptr;
  551. // Bind program
  552. if(hasTexture && texid.m_customProgram)
  553. {
  554. cmdb.bindShaderProgram(texid.m_customProgram);
  555. }
  556. else if(hasTexture)
  557. {
  558. cmdb.bindShaderProgram(m_grProgs[kRgbaTex].get());
  559. }
  560. else
  561. {
  562. cmdb.bindShaderProgram(m_grProgs[kNoTex].get());
  563. }
  564. // Bindings
  565. if(hasTexture)
  566. {
  567. cmdb.bindSampler(0, 0, (texid.m_pointSampling) ? m_nearestNearestRepeatSampler.get() : m_linearLinearRepeatSampler.get());
  568. cmdb.bindSrv(0, 0, TextureView(texid.m_texture, texid.m_textureSubresource));
  569. }
  570. // Push constants
  571. class PC
  572. {
  573. public:
  574. Vec4 m_transform;
  575. Array<U8, sizeof(AnKiImTextureID::m_extraFastConstants)> m_extra;
  576. } pc;
  577. pc.m_transform.x = 2.0f / drawData.DisplaySize.x;
  578. pc.m_transform.y = -2.0f / drawData.DisplaySize.y;
  579. pc.m_transform.z = (drawData.DisplayPos.x / drawData.DisplaySize.x) * 2.0f - 1.0f;
  580. pc.m_transform.w = -((drawData.DisplayPos.y / drawData.DisplaySize.y) * 2.0f - 1.0f);
  581. U32 extraFastConstantsSize = 0;
  582. if(hasTexture && texid.m_extraFastConstantsSize)
  583. {
  584. ANKI_ASSERT(texid.m_extraFastConstantsSize <= sizeof(texid.m_extraFastConstants));
  585. memcpy(&pc.m_extra[0], texid.m_extraFastConstants.getBegin(), texid.m_extraFastConstantsSize);
  586. extraFastConstantsSize = texid.m_extraFastConstantsSize;
  587. }
  588. cmdb.setFastConstants(&pc, sizeof(Vec4) + extraFastConstantsSize);
  589. // Draw
  590. cmdb.drawIndexed(PrimitiveTopology::kTriangles, pcmd.ElemCount, 1, idxOffset, vertOffset);
  591. }
  592. }
  593. idxOffset += pcmd.ElemCount;
  594. }
  595. vertOffset += cmdList.VtxBuffer.Size;
  596. }
  597. // Restore state
  598. cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
  599. cmdb.setCullMode(FaceSelectionBit::kBack);
  600. ImGui::SetCurrentContext(nullptr);
  601. }
  602. } // end namespace anki