Canvas.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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/Canvas.h>
  6. #include <AnKi/Ui/Font.h>
  7. #include <AnKi/Ui/UiManager.h>
  8. #include <AnKi/Resource/ResourceManager.h>
  9. #include <AnKi/GpuMemory/RebarTransientMemoryPool.h>
  10. #include <AnKi/Window/Input.h>
  11. #include <AnKi/Gr/Sampler.h>
  12. #include <AnKi/Gr/GrManager.h>
  13. namespace anki {
  14. static void setColorStyleAdia()
  15. {
  16. ImGuiStyle& style = ImGui::GetStyle();
  17. ImVec4* colors = style.Colors;
  18. // Base Colors
  19. const ImVec4 bgColor = ImVec4(0.10f, 0.105f, 0.11f, 1.00f);
  20. const ImVec4 lightBgColor = ImVec4(0.15f, 0.16f, 0.17f, 1.00f);
  21. const ImVec4 panelColor = ImVec4(0.17f, 0.18f, 0.19f, 1.00f);
  22. const ImVec4 panelHoverColor = ImVec4(0.20f, 0.22f, 0.24f, 1.00f);
  23. const ImVec4 panelActiveColor = ImVec4(0.23f, 0.26f, 0.29f, 1.00f);
  24. const ImVec4 textColor = ImVec4(0.86f, 0.87f, 0.88f, 1.00f);
  25. const ImVec4 textDisabledColor = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
  26. const ImVec4 borderColor = ImVec4(0.14f, 0.16f, 0.18f, 1.00f);
  27. const ImVec4 blueColor = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
  28. // Text
  29. colors[ImGuiCol_Text] = textColor;
  30. colors[ImGuiCol_TextDisabled] = textDisabledColor;
  31. // Windows
  32. colors[ImGuiCol_WindowBg] = bgColor;
  33. colors[ImGuiCol_ChildBg] = bgColor;
  34. colors[ImGuiCol_PopupBg] = bgColor;
  35. colors[ImGuiCol_Border] = borderColor;
  36. colors[ImGuiCol_BorderShadow] = borderColor;
  37. // Headers
  38. colors[ImGuiCol_Header] = panelColor;
  39. colors[ImGuiCol_HeaderHovered] = panelHoverColor;
  40. colors[ImGuiCol_HeaderActive] = panelActiveColor;
  41. // Buttons
  42. colors[ImGuiCol_Button] = panelColor;
  43. colors[ImGuiCol_ButtonHovered] = panelHoverColor;
  44. colors[ImGuiCol_ButtonActive] = panelActiveColor;
  45. // Frame BG
  46. colors[ImGuiCol_FrameBg] = lightBgColor;
  47. colors[ImGuiCol_FrameBgHovered] = panelHoverColor;
  48. colors[ImGuiCol_FrameBgActive] = panelActiveColor;
  49. // Tabs
  50. colors[ImGuiCol_Tab] = panelColor;
  51. colors[ImGuiCol_TabHovered] = panelHoverColor;
  52. colors[ImGuiCol_TabActive] = panelActiveColor;
  53. colors[ImGuiCol_TabUnfocused] = panelColor;
  54. colors[ImGuiCol_TabUnfocusedActive] = panelHoverColor;
  55. // Title
  56. colors[ImGuiCol_TitleBg] = bgColor;
  57. colors[ImGuiCol_TitleBgActive] = bgColor;
  58. colors[ImGuiCol_TitleBgCollapsed] = bgColor;
  59. // Scrollbar
  60. colors[ImGuiCol_ScrollbarBg] = bgColor;
  61. colors[ImGuiCol_ScrollbarGrab] = panelColor;
  62. colors[ImGuiCol_ScrollbarGrabHovered] = panelHoverColor;
  63. colors[ImGuiCol_ScrollbarGrabActive] = panelActiveColor;
  64. // Checkmark
  65. colors[ImGuiCol_CheckMark] = blueColor;
  66. // Slider
  67. colors[ImGuiCol_SliderGrab] = blueColor;
  68. colors[ImGuiCol_SliderGrabActive] = blueColor;
  69. // Resize Grip
  70. colors[ImGuiCol_ResizeGrip] = panelColor;
  71. colors[ImGuiCol_ResizeGripHovered] = panelHoverColor;
  72. colors[ImGuiCol_ResizeGripActive] = panelActiveColor;
  73. // Separator
  74. colors[ImGuiCol_Separator] = borderColor;
  75. colors[ImGuiCol_SeparatorHovered] = panelHoverColor;
  76. colors[ImGuiCol_SeparatorActive] = panelActiveColor;
  77. // Plot
  78. colors[ImGuiCol_PlotLines] = textColor;
  79. colors[ImGuiCol_PlotLinesHovered] = panelActiveColor;
  80. colors[ImGuiCol_PlotHistogram] = textColor;
  81. colors[ImGuiCol_PlotHistogramHovered] = panelActiveColor;
  82. // Text Selected BG
  83. colors[ImGuiCol_TextSelectedBg] = panelActiveColor;
  84. // Modal Window Dim Bg
  85. colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.10f, 0.105f, 0.11f, 0.5f);
  86. // Tables
  87. colors[ImGuiCol_TableHeaderBg] = panelColor;
  88. colors[ImGuiCol_TableBorderStrong] = borderColor;
  89. colors[ImGuiCol_TableBorderLight] = borderColor;
  90. colors[ImGuiCol_TableRowBg] = bgColor;
  91. colors[ImGuiCol_TableRowBgAlt] = lightBgColor;
  92. // Styles
  93. style.FrameBorderSize = 1.0f;
  94. style.FrameRounding = 2.0f;
  95. style.WindowBorderSize = 1.0f;
  96. style.PopupBorderSize = 1.0f;
  97. style.ScrollbarSize = 12.0f;
  98. style.ScrollbarRounding = 2.0f;
  99. style.GrabMinSize = 7.0f;
  100. style.GrabRounding = 2.0f;
  101. style.TabBorderSize = 1.0f;
  102. style.TabRounding = 2.0f;
  103. // Reduced Padding and Spacing
  104. style.WindowPadding = ImVec2(5.0f, 5.0f);
  105. style.FramePadding = ImVec2(4.0f, 3.0f);
  106. style.ItemSpacing = ImVec2(6.0f, 4.0f);
  107. style.ItemInnerSpacing = ImVec2(4.0f, 4.0f);
  108. }
  109. Canvas::~Canvas()
  110. {
  111. if(m_imCtx)
  112. {
  113. ImGui::DestroyContext(m_imCtx);
  114. }
  115. }
  116. Error Canvas::init(Font* font, U32 fontHeight, U32 width, U32 height)
  117. {
  118. ANKI_ASSERT(font);
  119. m_font.reset(font);
  120. m_dfltFontHeight = fontHeight;
  121. resize(width, height);
  122. // Create program
  123. ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/Ui.ankiprogbin", m_prog));
  124. for(U32 i = 0; i < kShaderCount; ++i)
  125. {
  126. const ShaderProgramResourceVariant* variant;
  127. ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
  128. variantInitInfo.addMutation("TEXTURE_TYPE", i);
  129. m_prog->getOrCreateVariant(variantInitInfo, variant);
  130. m_grProgs[i].reset(&variant->getProgram());
  131. }
  132. // Sampler
  133. SamplerInitInfo samplerInit("Canvas");
  134. samplerInit.m_minMagFilter = SamplingFilter::kLinear;
  135. samplerInit.m_mipmapFilter = SamplingFilter::kLinear;
  136. samplerInit.m_addressing = SamplingAddressing::kRepeat;
  137. m_linearLinearRepeatSampler = GrManager::getSingleton().newSampler(samplerInit);
  138. samplerInit.m_minMagFilter = SamplingFilter::kNearest;
  139. samplerInit.m_mipmapFilter = SamplingFilter::kNearest;
  140. m_nearestNearestRepeatSampler = GrManager::getSingleton().newSampler(samplerInit);
  141. // Create the context
  142. m_imCtx = ImGui::CreateContext(font->getImFontAtlas());
  143. ImGui::SetCurrentContext(m_imCtx);
  144. ImGui::GetIO().IniFilename = nullptr;
  145. ImGui::GetIO().LogFilename = nullptr;
  146. // ImGui::StyleColorsLight();
  147. setColorStyleAdia();
  148. #define ANKI_HANDLE(ak, im) ImGui::GetIO().KeyMap[im] = static_cast<int>(ak);
  149. ANKI_HANDLE(KeyCode::kTab, ImGuiKey_Tab)
  150. ANKI_HANDLE(KeyCode::kLeft, ImGuiKey_LeftArrow)
  151. ANKI_HANDLE(KeyCode::kRight, ImGuiKey_RightArrow)
  152. ANKI_HANDLE(KeyCode::kUp, ImGuiKey_UpArrow)
  153. ANKI_HANDLE(KeyCode::kDown, ImGuiKey_DownArrow)
  154. ANKI_HANDLE(KeyCode::kPageUp, ImGuiKey_PageUp)
  155. ANKI_HANDLE(KeyCode::kPageDown, ImGuiKey_PageDown)
  156. ANKI_HANDLE(KeyCode::kHome, ImGuiKey_Home)
  157. ANKI_HANDLE(KeyCode::kEnd, ImGuiKey_End)
  158. ANKI_HANDLE(KeyCode::kInsert, ImGuiKey_Insert)
  159. ANKI_HANDLE(KeyCode::kDelete, ImGuiKey_Delete)
  160. ANKI_HANDLE(KeyCode::kBackspace, ImGuiKey_Backspace)
  161. ANKI_HANDLE(KeyCode::kSpace, ImGuiKey_Space)
  162. ANKI_HANDLE(KeyCode::kReturn, ImGuiKey_Enter)
  163. // ANKI_HANDLE(KeyCode::RETURN2, ImGuiKey_Enter)
  164. ANKI_HANDLE(KeyCode::kEscape, ImGuiKey_Escape)
  165. ANKI_HANDLE(KeyCode::kA, ImGuiKey_A)
  166. ANKI_HANDLE(KeyCode::kC, ImGuiKey_C)
  167. ANKI_HANDLE(KeyCode::kV, ImGuiKey_V)
  168. ANKI_HANDLE(KeyCode::kX, ImGuiKey_X)
  169. ANKI_HANDLE(KeyCode::kY, ImGuiKey_Y)
  170. ANKI_HANDLE(KeyCode::kZ, ImGuiKey_Z)
  171. #undef ANKI_HANDLE
  172. ImGui::SetCurrentContext(nullptr);
  173. return Error::kNone;
  174. }
  175. void Canvas::handleInput()
  176. {
  177. const Input& in = Input::getSingleton();
  178. // Begin
  179. ImGui::SetCurrentContext(m_imCtx);
  180. ImGuiIO& io = ImGui::GetIO();
  181. // Handle mouse
  182. Array<U32, 4> viewport = {0, 0, m_width, m_height};
  183. Vec2 mousePosf = in.getMousePosition() / 2.0f + 0.5f;
  184. mousePosf.y() = 1.0f - mousePosf.y();
  185. const UVec2 mousePos(U32(mousePosf.x() * F32(viewport[2])), U32(mousePosf.y() * F32(viewport[3])));
  186. io.MousePos.x = F32(mousePos.x());
  187. io.MousePos.y = F32(mousePos.y());
  188. io.MouseClicked[0] = in.getMouseButton(MouseButton::kLeft) == 1;
  189. io.MouseDown[0] = in.getMouseButton(MouseButton::kLeft) > 0;
  190. if(in.getMouseButton(MouseButton::kScrollUp) == 1)
  191. {
  192. io.MouseWheel = F32(in.getMouseButton(MouseButton::kScrollUp));
  193. }
  194. else if(in.getMouseButton(MouseButton::kScrollDown) == 1)
  195. {
  196. io.MouseWheel = -F32(in.getMouseButton(MouseButton::kScrollDown));
  197. }
  198. io.KeyCtrl = (in.getKey(KeyCode::kLeftCtrl) || in.getKey(KeyCode::kRightCtrl));
  199. // Handle keyboard
  200. #define ANKI_HANDLE(ak) io.KeysDown[int(ak)] = (in.getKey(ak) == 1);
  201. ANKI_HANDLE(KeyCode::kTab)
  202. ANKI_HANDLE(KeyCode::kLeft)
  203. ANKI_HANDLE(KeyCode::kRight)
  204. ANKI_HANDLE(KeyCode::kUp)
  205. ANKI_HANDLE(KeyCode::kDown)
  206. ANKI_HANDLE(KeyCode::kPageUp)
  207. ANKI_HANDLE(KeyCode::kPageDown)
  208. ANKI_HANDLE(KeyCode::kHome)
  209. ANKI_HANDLE(KeyCode::kEnd)
  210. ANKI_HANDLE(KeyCode::kInsert)
  211. ANKI_HANDLE(KeyCode::kDelete)
  212. ANKI_HANDLE(KeyCode::kBackspace)
  213. ANKI_HANDLE(KeyCode::kSpace)
  214. ANKI_HANDLE(KeyCode::kReturn)
  215. // ANKI_HANDLE(KeyCode::RETURN2)
  216. ANKI_HANDLE(KeyCode::kEscape)
  217. ANKI_HANDLE(KeyCode::kA)
  218. ANKI_HANDLE(KeyCode::kC)
  219. ANKI_HANDLE(KeyCode::kV)
  220. ANKI_HANDLE(KeyCode::kX)
  221. ANKI_HANDLE(KeyCode::kY)
  222. ANKI_HANDLE(KeyCode::kZ)
  223. #undef ANKI_HANDLE
  224. io.AddInputCharactersUTF8(in.getTextInput().cstr());
  225. // End
  226. ImGui::SetCurrentContext(nullptr);
  227. }
  228. void Canvas::beginBuilding()
  229. {
  230. ImGui::SetCurrentContext(m_imCtx);
  231. ImGuiIO& io = ImGui::GetIO();
  232. io.DeltaTime = 1.0f / 60.0f;
  233. io.DisplaySize = ImVec2(F32(m_width), F32(m_height));
  234. ImGui::NewFrame();
  235. ImGui::PushFont(&m_font->getImFont(m_dfltFontHeight));
  236. }
  237. void Canvas::pushFont(Font* font, U32 fontHeight)
  238. {
  239. m_references.pushBack(UiObjectPtr(font));
  240. ImGui::PushFont(&font->getImFont(fontHeight));
  241. }
  242. void Canvas::appendToCommandBuffer(CommandBuffer& cmdb)
  243. {
  244. appendToCommandBufferInternal(cmdb);
  245. // Done
  246. ImGui::SetCurrentContext(nullptr);
  247. m_references.destroy();
  248. }
  249. void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
  250. {
  251. ImGui::PopFont();
  252. ImGui::Render();
  253. ImDrawData& drawData = *ImGui::GetDrawData();
  254. // Allocate index and vertex buffers
  255. BufferView vertsToken, indicesToken;
  256. {
  257. if(drawData.TotalVtxCount == 0 || drawData.TotalIdxCount == 0)
  258. {
  259. return;
  260. }
  261. ImDrawVert* verts;
  262. vertsToken = RebarTransientMemoryPool::getSingleton().allocate(drawData.TotalVtxCount * sizeof(ImDrawVert), sizeof(F32), verts);
  263. ImDrawIdx* indices;
  264. indicesToken = RebarTransientMemoryPool::getSingleton().allocate(drawData.TotalIdxCount * sizeof(ImDrawIdx), sizeof(ImDrawIdx), indices);
  265. for(I n = 0; n < drawData.CmdListsCount; ++n)
  266. {
  267. const ImDrawList& cmdList = *drawData.CmdLists[n];
  268. memcpy(verts, cmdList.VtxBuffer.Data, cmdList.VtxBuffer.Size * sizeof(ImDrawVert));
  269. memcpy(indices, cmdList.IdxBuffer.Data, cmdList.IdxBuffer.Size * sizeof(ImDrawIdx));
  270. verts += cmdList.VtxBuffer.Size;
  271. indices += cmdList.IdxBuffer.Size;
  272. }
  273. }
  274. cmdb.setBlendFactors(0, BlendFactor::kSrcAlpha, BlendFactor::kOneMinusSrcAlpha);
  275. cmdb.setCullMode(FaceSelectionBit::kNone);
  276. const F32 fbWidth = drawData.DisplaySize.x * drawData.FramebufferScale.x;
  277. const F32 fbHeight = drawData.DisplaySize.y * drawData.FramebufferScale.y;
  278. cmdb.setViewport(0, 0, U32(fbWidth), U32(fbHeight));
  279. cmdb.bindVertexBuffer(0, vertsToken, sizeof(ImDrawVert));
  280. cmdb.setVertexAttribute(VertexAttributeSemantic::kPosition, 0, Format::kR32G32_Sfloat, 0);
  281. cmdb.setVertexAttribute(VertexAttributeSemantic::kColor, 0, Format::kR8G8B8A8_Unorm, sizeof(Vec2) * 2);
  282. cmdb.setVertexAttribute(VertexAttributeSemantic::kTexCoord, 0, Format::kR32G32_Sfloat, sizeof(Vec2));
  283. cmdb.bindIndexBuffer(indicesToken, IndexType::kU16);
  284. // Will project scissor/clipping rectangles into framebuffer space
  285. const Vec2 clipOff = drawData.DisplayPos; // (0,0) unless using multi-viewports
  286. const Vec2 clipScale = drawData.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
  287. // Render
  288. U32 vertOffset = 0;
  289. U32 idxOffset = 0;
  290. for(I32 n = 0; n < drawData.CmdListsCount; n++)
  291. {
  292. const ImDrawList& cmdList = *drawData.CmdLists[n];
  293. for(I32 i = 0; i < cmdList.CmdBuffer.Size; i++)
  294. {
  295. const ImDrawCmd& pcmd = cmdList.CmdBuffer[i];
  296. if(pcmd.UserCallback)
  297. {
  298. // User callback (registered via ImDrawList::AddCallback), ignore
  299. ANKI_UI_LOGW("Got user callback. Will ignore");
  300. }
  301. else
  302. {
  303. // Project scissor/clipping rectangles into framebuffer space
  304. Vec4 clipRect;
  305. clipRect.x() = (pcmd.ClipRect.x - clipOff.x()) * clipScale.x();
  306. clipRect.y() = (pcmd.ClipRect.y - clipOff.y()) * clipScale.y();
  307. clipRect.z() = (pcmd.ClipRect.z - clipOff.x()) * clipScale.x();
  308. clipRect.w() = (pcmd.ClipRect.w - clipOff.y()) * clipScale.y();
  309. if(clipRect.x() < fbWidth && clipRect.y() < fbHeight && clipRect.z() >= 0.0f && clipRect.w() >= 0.0f)
  310. {
  311. // Negative offsets are illegal for vkCmdSetScissor
  312. if(clipRect.x() < 0.0f)
  313. {
  314. clipRect.x() = 0.0f;
  315. }
  316. if(clipRect.y() < 0.0f)
  317. {
  318. clipRect.y() = 0.0f;
  319. }
  320. // Apply scissor/clipping rectangle
  321. cmdb.setScissor(U32(clipRect.x()), U32(clipRect.y()), U32(clipRect.z() - clipRect.x()), U32(clipRect.w() - clipRect.y()));
  322. UiImageId id(pcmd.TextureId);
  323. const UiImageIdData* data = id.m_data;
  324. // Bind program
  325. if(data && data->m_customProgram.isCreated())
  326. {
  327. cmdb.bindShaderProgram(data->m_customProgram.get());
  328. }
  329. else if(data && data->m_textureView.isValid())
  330. {
  331. cmdb.bindShaderProgram(m_grProgs[kRgbaTex].get());
  332. }
  333. else
  334. {
  335. cmdb.bindShaderProgram(m_grProgs[kNoTex].get());
  336. }
  337. // Bindings
  338. if(data && data->m_textureView.isValid())
  339. {
  340. cmdb.bindSampler(0, 0, (data->m_pointSampling) ? m_nearestNearestRepeatSampler.get() : m_linearLinearRepeatSampler.get());
  341. cmdb.bindSrv(0, 0, data->m_textureView);
  342. }
  343. // Push constants
  344. class PC
  345. {
  346. public:
  347. Vec4 m_transform;
  348. Array<U8, sizeof(UiImageIdData::m_extraFastConstants)> m_extra;
  349. } pc;
  350. pc.m_transform.x() = 2.0f / drawData.DisplaySize.x;
  351. pc.m_transform.y() = -2.0f / drawData.DisplaySize.y;
  352. pc.m_transform.z() = (drawData.DisplayPos.x / drawData.DisplaySize.x) * 2.0f - 1.0f;
  353. pc.m_transform.w() = -((drawData.DisplayPos.y / drawData.DisplaySize.y) * 2.0f - 1.0f);
  354. U32 extraFastConstantsSize = 0;
  355. if(data && data->m_extraFastConstantsSize)
  356. {
  357. ANKI_ASSERT(data->m_extraFastConstantsSize <= sizeof(data->m_extraFastConstants));
  358. memcpy(&pc.m_extra[0], data->m_extraFastConstants.getBegin(), data->m_extraFastConstantsSize);
  359. extraFastConstantsSize = data->m_extraFastConstantsSize;
  360. }
  361. cmdb.setFastConstants(&pc, sizeof(Vec4) + extraFastConstantsSize);
  362. // Draw
  363. cmdb.drawIndexed(PrimitiveTopology::kTriangles, pcmd.ElemCount, 1, idxOffset, vertOffset);
  364. }
  365. }
  366. idxOffset += pcmd.ElemCount;
  367. }
  368. vertOffset += cmdList.VtxBuffer.Size;
  369. }
  370. // Restore state
  371. cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
  372. cmdb.setCullMode(FaceSelectionBit::kBack);
  373. }
  374. } // end namespace anki