ImGuiLayer.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Copyright 2017 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "tools/viewer/ImGuiLayer.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkImage.h"
  10. #include "include/core/SkPixmap.h"
  11. #include "include/core/SkSurface.h"
  12. #include "include/core/SkSwizzle.h"
  13. #include "include/core/SkTime.h"
  14. #include "include/core/SkVertices.h"
  15. #include "imgui.h"
  16. #include <stdlib.h>
  17. #include <map>
  18. using namespace sk_app;
  19. ImGuiLayer::ImGuiLayer() {
  20. // ImGui initialization:
  21. ImGui::CreateContext();
  22. ImGuiIO& io = ImGui::GetIO();
  23. // Keymap...
  24. io.KeyMap[ImGuiKey_Tab] = (int)Window::Key::kTab;
  25. io.KeyMap[ImGuiKey_LeftArrow] = (int)Window::Key::kLeft;
  26. io.KeyMap[ImGuiKey_RightArrow] = (int)Window::Key::kRight;
  27. io.KeyMap[ImGuiKey_UpArrow] = (int)Window::Key::kUp;
  28. io.KeyMap[ImGuiKey_DownArrow] = (int)Window::Key::kDown;
  29. io.KeyMap[ImGuiKey_PageUp] = (int)Window::Key::kPageUp;
  30. io.KeyMap[ImGuiKey_PageDown] = (int)Window::Key::kPageDown;
  31. io.KeyMap[ImGuiKey_Home] = (int)Window::Key::kHome;
  32. io.KeyMap[ImGuiKey_End] = (int)Window::Key::kEnd;
  33. io.KeyMap[ImGuiKey_Delete] = (int)Window::Key::kDelete;
  34. io.KeyMap[ImGuiKey_Backspace] = (int)Window::Key::kBack;
  35. io.KeyMap[ImGuiKey_Enter] = (int)Window::Key::kOK;
  36. io.KeyMap[ImGuiKey_Escape] = (int)Window::Key::kEscape;
  37. io.KeyMap[ImGuiKey_A] = (int)Window::Key::kA;
  38. io.KeyMap[ImGuiKey_C] = (int)Window::Key::kC;
  39. io.KeyMap[ImGuiKey_V] = (int)Window::Key::kV;
  40. io.KeyMap[ImGuiKey_X] = (int)Window::Key::kX;
  41. io.KeyMap[ImGuiKey_Y] = (int)Window::Key::kY;
  42. io.KeyMap[ImGuiKey_Z] = (int)Window::Key::kZ;
  43. int w, h;
  44. unsigned char* pixels;
  45. io.Fonts->GetTexDataAsAlpha8(&pixels, &w, &h);
  46. SkImageInfo info = SkImageInfo::MakeA8(w, h);
  47. SkPixmap pmap(info, pixels, info.minRowBytes());
  48. SkMatrix localMatrix = SkMatrix::MakeScale(1.0f / w, 1.0f / h);
  49. auto fontImage = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
  50. auto fontShader = fontImage->makeShader(&localMatrix);
  51. fFontPaint.setShader(fontShader);
  52. fFontPaint.setColor(SK_ColorWHITE);
  53. fFontPaint.setFilterQuality(kLow_SkFilterQuality);
  54. io.Fonts->TexID = &fFontPaint;
  55. }
  56. ImGuiLayer::~ImGuiLayer() {
  57. ImGui::DestroyContext();
  58. }
  59. void ImGuiLayer::onAttach(Window* window) {
  60. fWindow = window;
  61. }
  62. bool ImGuiLayer::onMouse(int x, int y, InputState state, ModifierKey modifiers) {
  63. ImGuiIO& io = ImGui::GetIO();
  64. io.MousePos.x = static_cast<float>(x);
  65. io.MousePos.y = static_cast<float>(y);
  66. if (InputState::kDown == state) {
  67. io.MouseDown[0] = true;
  68. } else if (InputState::kUp == state) {
  69. io.MouseDown[0] = false;
  70. }
  71. return io.WantCaptureMouse;
  72. }
  73. bool ImGuiLayer::onMouseWheel(float delta, ModifierKey modifiers) {
  74. ImGuiIO& io = ImGui::GetIO();
  75. io.MouseWheel += delta;
  76. return true;
  77. }
  78. void ImGuiLayer::skiaWidget(const ImVec2& size, SkiaWidgetFunc func) {
  79. intptr_t funcIndex = fSkiaWidgetFuncs.count();
  80. fSkiaWidgetFuncs.push_back(func);
  81. ImGui::Image((ImTextureID)funcIndex, size);
  82. }
  83. void ImGuiLayer::onPrePaint() {
  84. // Update ImGui input
  85. ImGuiIO& io = ImGui::GetIO();
  86. static double previousTime = 0.0;
  87. double currentTime = SkTime::GetSecs();
  88. io.DeltaTime = static_cast<float>(currentTime - previousTime);
  89. previousTime = currentTime;
  90. io.DisplaySize.x = static_cast<float>(fWindow->width());
  91. io.DisplaySize.y = static_cast<float>(fWindow->height());
  92. io.KeyAlt = io.KeysDown[static_cast<int>(Window::Key::kOption)];
  93. io.KeyCtrl = io.KeysDown[static_cast<int>(Window::Key::kCtrl)];
  94. io.KeyShift = io.KeysDown[static_cast<int>(Window::Key::kShift)];
  95. ImGui::NewFrame();
  96. }
  97. void ImGuiLayer::onPaint(SkSurface* surface) {
  98. // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands
  99. // (widgets, etc...) that have been issued
  100. ImGui::Render();
  101. // Then we fetch the most recent data, and convert it so we can render with Skia
  102. const ImDrawData* drawData = ImGui::GetDrawData();
  103. SkTDArray<SkPoint> pos;
  104. SkTDArray<SkPoint> uv;
  105. SkTDArray<SkColor> color;
  106. auto canvas = surface->getCanvas();
  107. for (int i = 0; i < drawData->CmdListsCount; ++i) {
  108. const ImDrawList* drawList = drawData->CmdLists[i];
  109. // De-interleave all vertex data (sigh), convert to Skia types
  110. pos.rewind(); uv.rewind(); color.rewind();
  111. for (int j = 0; j < drawList->VtxBuffer.size(); ++j) {
  112. const ImDrawVert& vert = drawList->VtxBuffer[j];
  113. pos.push_back(SkPoint::Make(vert.pos.x, vert.pos.y));
  114. uv.push_back(SkPoint::Make(vert.uv.x, vert.uv.y));
  115. color.push_back(vert.col);
  116. }
  117. // ImGui colors are RGBA
  118. SkSwapRB(color.begin(), color.begin(), color.count());
  119. int indexOffset = 0;
  120. // Draw everything with canvas.drawVertices...
  121. for (int j = 0; j < drawList->CmdBuffer.size(); ++j) {
  122. const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j];
  123. SkAutoCanvasRestore acr(canvas, true);
  124. // TODO: Find min/max index for each draw, so we know how many vertices (sigh)
  125. if (drawCmd->UserCallback) {
  126. drawCmd->UserCallback(drawList, drawCmd);
  127. } else {
  128. intptr_t idIndex = (intptr_t)drawCmd->TextureId;
  129. if (idIndex < fSkiaWidgetFuncs.count()) {
  130. // Small image IDs are actually indices into a list of callbacks. We directly
  131. // examing the vertex data to deduce the image rectangle, then reconfigure the
  132. // canvas to be clipped and translated so that the callback code gets to use
  133. // Skia to render a widget in the middle of an ImGui panel.
  134. ImDrawIdx rectIndex = drawList->IdxBuffer[indexOffset];
  135. SkPoint tl = pos[rectIndex], br = pos[rectIndex + 2];
  136. canvas->clipRect(SkRect::MakeLTRB(tl.fX, tl.fY, br.fX, br.fY));
  137. canvas->translate(tl.fX, tl.fY);
  138. fSkiaWidgetFuncs[idIndex](canvas);
  139. } else {
  140. SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId);
  141. SkASSERT(paint);
  142. canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y,
  143. drawCmd->ClipRect.z, drawCmd->ClipRect.w));
  144. auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
  145. drawList->VtxBuffer.size(),
  146. pos.begin(), uv.begin(), color.begin(),
  147. drawCmd->ElemCount,
  148. drawList->IdxBuffer.begin() + indexOffset);
  149. canvas->drawVertices(vertices, SkBlendMode::kModulate, *paint);
  150. }
  151. indexOffset += drawCmd->ElemCount;
  152. }
  153. }
  154. }
  155. fSkiaWidgetFuncs.reset();
  156. }
  157. bool ImGuiLayer::onKey(sk_app::Window::Key key, InputState state, ModifierKey modifiers) {
  158. ImGuiIO& io = ImGui::GetIO();
  159. io.KeysDown[static_cast<int>(key)] = (InputState::kDown == state);
  160. return io.WantCaptureKeyboard;
  161. }
  162. bool ImGuiLayer::onChar(SkUnichar c, ModifierKey modifiers) {
  163. ImGuiIO& io = ImGui::GetIO();
  164. if (io.WantTextInput) {
  165. if (c > 0 && c < 0x10000) {
  166. io.AddInputCharacter(c);
  167. }
  168. return true;
  169. }
  170. return false;
  171. }