ImGuiMenu.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. ////////////////////////////////////////////////////////////////////////////////
  2. #include "ImGuiMenu.h"
  3. #include <igl/project.h>
  4. #include <imgui/imgui.h>
  5. #include <imgui_impl_glfw_gl3.h>
  6. #include <imgui_fonts_droid_sans.h>
  7. #include <GLFW/glfw3.h>
  8. #include <iostream>
  9. ////////////////////////////////////////////////////////////////////////////////
  10. namespace igl
  11. {
  12. namespace opengl
  13. {
  14. namespace glfw
  15. {
  16. namespace imgui
  17. {
  18. IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
  19. {
  20. ViewerPlugin::init(_viewer);
  21. // Setup ImGui binding
  22. if (_viewer)
  23. {
  24. if (m_Context == nullptr)
  25. {
  26. m_Context = ImGui::CreateContext();
  27. }
  28. ImGui_ImplGlfwGL3_Init(viewer->window, false);
  29. ImGui::GetIO().IniFilename = nullptr;
  30. ImGui::StyleColorsDark();
  31. ImGuiStyle& style = ImGui::GetStyle();
  32. style.FrameRounding = 5.0f;
  33. reload_font();
  34. }
  35. }
  36. IGL_INLINE void ImGuiMenu::reload_font(int font_size)
  37. {
  38. m_HidpiScaling = hidpi_scaling();
  39. m_PixelRatio = pixel_ratio();
  40. ImGuiIO& io = ImGui::GetIO();
  41. io.Fonts->Clear();
  42. io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
  43. droid_sans_compressed_size, font_size * m_HidpiScaling);
  44. io.FontGlobalScale = 1.0 / m_PixelRatio;
  45. }
  46. IGL_INLINE void ImGuiMenu::shutdown()
  47. {
  48. // Cleanup
  49. ImGui_ImplGlfwGL3_Shutdown();
  50. ImGui::DestroyContext(m_Context);
  51. m_Context = nullptr;
  52. }
  53. IGL_INLINE bool ImGuiMenu::pre_draw()
  54. {
  55. glfwPollEvents();
  56. // Check whether window dpi has changed
  57. float scaling = hidpi_scaling();
  58. if (std::abs(scaling - m_HidpiScaling) > 1e-5)
  59. {
  60. reload_font();
  61. ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
  62. }
  63. ImGui_ImplGlfwGL3_NewFrame();
  64. return false;
  65. }
  66. IGL_INLINE bool ImGuiMenu::post_draw()
  67. {
  68. draw_menu();
  69. ImGui::Render();
  70. return false;
  71. }
  72. IGL_INLINE void ImGuiMenu::post_resize(int width, int height)
  73. {
  74. if (m_Context)
  75. {
  76. ImGui::GetIO().DisplaySize.x = float(width);
  77. ImGui::GetIO().DisplaySize.y = float(height);
  78. }
  79. }
  80. // Mouse IO
  81. IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier)
  82. {
  83. ImGui_ImplGlfwGL3_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
  84. return ImGui::GetIO().WantCaptureMouse;
  85. }
  86. IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier)
  87. {
  88. return ImGui::GetIO().WantCaptureMouse;
  89. }
  90. IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y)
  91. {
  92. return ImGui::GetIO().WantCaptureMouse;
  93. }
  94. IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y)
  95. {
  96. ImGui_ImplGlfwGL3_ScrollCallback(viewer->window, 0.f, delta_y);
  97. return ImGui::GetIO().WantCaptureMouse;
  98. }
  99. // Keyboard IO
  100. IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers)
  101. {
  102. ImGui_ImplGlfwGL3_CharCallback(nullptr, key);
  103. return ImGui::GetIO().WantCaptureKeyboard;
  104. }
  105. IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers)
  106. {
  107. ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
  108. return ImGui::GetIO().WantCaptureKeyboard;
  109. }
  110. IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
  111. {
  112. ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
  113. return ImGui::GetIO().WantCaptureKeyboard;
  114. }
  115. // Draw menu
  116. IGL_INLINE void ImGuiMenu::draw_menu()
  117. {
  118. // Text labels
  119. draw_labels_menu();
  120. // Viewer settings
  121. float menu_width = 180.f * menu_scaling();
  122. ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
  123. ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
  124. ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f));
  125. bool _viewer_menu_visible = true;
  126. ImGui::Begin(
  127. "Viewer", &_viewer_menu_visible,
  128. ImGuiWindowFlags_NoSavedSettings
  129. | ImGuiWindowFlags_AlwaysAutoResize
  130. );
  131. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f);
  132. draw_viewer_menu();
  133. ImGui::PopItemWidth();
  134. ImGui::End();
  135. // Other menus
  136. draw_other_menu();
  137. }
  138. IGL_INLINE void ImGuiMenu::draw_viewer_menu()
  139. {
  140. // Workspace
  141. if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen))
  142. {
  143. ImGui::Columns(2, nullptr, false);
  144. if (ImGui::Button("Load##Workspace", ImVec2(-1, 0)))
  145. {
  146. viewer->load_scene();
  147. }
  148. ImGui::NextColumn();
  149. if (ImGui::Button("Save##Workspace", ImVec2(-1, 0)))
  150. {
  151. viewer->save_scene();
  152. }
  153. ImGui::Columns(1);
  154. }
  155. // Mesh
  156. if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen))
  157. {
  158. ImGui::Columns(2, nullptr, false);
  159. if (ImGui::Button("Load##Mesh", ImVec2(-1, 0)))
  160. {
  161. viewer->open_dialog_load_mesh();
  162. }
  163. ImGui::NextColumn();
  164. if (ImGui::Button("Save##Mesh", ImVec2(-1, 0)))
  165. {
  166. viewer->open_dialog_save_mesh();
  167. }
  168. ImGui::Columns(1);
  169. }
  170. // Viewing options
  171. if (ImGui::CollapsingHeader("Viewing Options", ImGuiTreeNodeFlags_DefaultOpen))
  172. {
  173. if (ImGui::Button("Center object", ImVec2(-1, 0)))
  174. {
  175. viewer->core.align_camera_center(viewer->data().V, viewer->data().F);
  176. }
  177. if (ImGui::Button("Snap canonical view", ImVec2(-1, 0)))
  178. {
  179. viewer->snap_to_canonical_quaternion();
  180. }
  181. // Zoom
  182. ImGui::PushItemWidth(80 * menu_scaling());
  183. ImGui::DragFloat("Zoom", &(viewer->core.camera_zoom), 0.05f, 0.1f, 20.0f);
  184. // Select rotation type
  185. static int rotation_type = static_cast<int>(viewer->core.rotation_type);
  186. static Eigen::Quaternionf trackball_angle = Eigen::Quaternionf::Identity();
  187. static bool orthographic = true;
  188. if (ImGui::Combo("Camera Type", &rotation_type, "Trackball\0Two Axes\0002D Mode\0\0"))
  189. {
  190. using RT = igl::opengl::ViewerCore::RotationType;
  191. auto new_type = static_cast<RT>(rotation_type);
  192. if (new_type != viewer->core.rotation_type)
  193. {
  194. if (new_type == RT::ROTATION_TYPE_NO_ROTATION)
  195. {
  196. trackball_angle = viewer->core.trackball_angle;
  197. orthographic = viewer->core.orthographic;
  198. viewer->core.trackball_angle = Eigen::Quaternionf::Identity();
  199. viewer->core.orthographic = true;
  200. }
  201. else if (viewer->core.rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
  202. {
  203. viewer->core.trackball_angle = trackball_angle;
  204. viewer->core.orthographic = orthographic;
  205. }
  206. viewer->core.set_rotation_type(new_type);
  207. }
  208. }
  209. // Orthographic view
  210. ImGui::Checkbox("Orthographic view", &(viewer->core.orthographic));
  211. ImGui::PopItemWidth();
  212. }
  213. // Draw options
  214. if (ImGui::CollapsingHeader("Draw Options", ImGuiTreeNodeFlags_DefaultOpen))
  215. {
  216. if (ImGui::Checkbox("Face-based", &(viewer->data().face_based)))
  217. {
  218. viewer->data().set_face_based(viewer->data().face_based);
  219. }
  220. ImGui::Checkbox("Show texture", &(viewer->data().show_texture));
  221. if (ImGui::Checkbox("Invert normals", &(viewer->data().invert_normals)))
  222. {
  223. viewer->data().dirty |= igl::opengl::MeshGL::DIRTY_NORMAL;
  224. }
  225. ImGui::Checkbox("Show overlay", &(viewer->data().show_overlay));
  226. ImGui::Checkbox("Show overlay depth", &(viewer->data().show_overlay_depth));
  227. ImGui::ColorEdit4("Background", viewer->core.background_color.data(),
  228. ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
  229. ImGui::ColorEdit4("Line color", viewer->data().line_color.data(),
  230. ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
  231. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.3f);
  232. ImGui::DragFloat("Shininess", &(viewer->data().shininess), 0.05f, 0.0f, 100.0f);
  233. ImGui::PopItemWidth();
  234. }
  235. // Overlays
  236. if (ImGui::CollapsingHeader("Overlays", ImGuiTreeNodeFlags_DefaultOpen))
  237. {
  238. ImGui::Checkbox("Wireframe", &(viewer->data().show_lines));
  239. ImGui::Checkbox("Fill", &(viewer->data().show_faces));
  240. ImGui::Checkbox("Show vertex labels", &(viewer->data().show_vertid));
  241. ImGui::Checkbox("Show faces labels", &(viewer->data().show_faceid));
  242. }
  243. }
  244. IGL_INLINE void ImGuiMenu::draw_labels_menu()
  245. {
  246. // Text labels
  247. ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiSetCond_Always);
  248. ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiSetCond_Always);
  249. bool visible = true;
  250. ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,0));
  251. ImGui::Begin("ViewerLabels", &visible,
  252. ImGuiWindowFlags_NoTitleBar
  253. | ImGuiWindowFlags_NoResize
  254. | ImGuiWindowFlags_NoMove
  255. | ImGuiWindowFlags_NoScrollbar
  256. | ImGuiWindowFlags_NoScrollWithMouse
  257. | ImGuiWindowFlags_NoCollapse
  258. | ImGuiWindowFlags_NoSavedSettings
  259. | ImGuiWindowFlags_NoInputs);
  260. draw_labels(viewer->data());
  261. ImGui::End();
  262. ImGui::PopStyleColor();
  263. }
  264. IGL_INLINE void ImGuiMenu::draw_labels(const igl::opengl::ViewerData &data)
  265. {
  266. if (data.show_vertid)
  267. {
  268. for (int i = 0; i < data.V.rows(); ++i)
  269. {
  270. draw_text(data.V.row(i), data.V_normals.row(i), std::to_string(i));
  271. }
  272. }
  273. if (data.show_faceid)
  274. {
  275. for (int i = 0; i < data.F.rows(); ++i)
  276. {
  277. Eigen::RowVector3d p = Eigen::RowVector3d::Zero();
  278. for (int j = 0; j < data.F.cols(); ++j)
  279. {
  280. p += data.V.row(data.F(i,j));
  281. }
  282. p /= (double) data.F.cols();
  283. draw_text(p, data.F_normals.row(i), std::to_string(i));
  284. }
  285. }
  286. if (data.labels_positions.rows() > 0)
  287. {
  288. for (int i = 0; i < data.labels_positions.rows(); ++i)
  289. {
  290. draw_text(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
  291. data.labels_strings[i]);
  292. }
  293. }
  294. }
  295. IGL_INLINE void ImGuiMenu::draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
  296. {
  297. Eigen::Matrix4f view_matrix = viewer->core.view * viewer->core.model;
  298. pos += normal * 0.005f * viewer->core.object_scale;
  299. Eigen::Vector3f coord = igl::project(Eigen::Vector3f(pos.cast<float>()),
  300. view_matrix, viewer->core.proj, viewer->core.viewport);
  301. // Draw text labels slightly bigger than normal text
  302. ImDrawList* drawList = ImGui::GetWindowDrawList();
  303. drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize() * 1.2,
  304. ImVec2(coord[0]/m_PixelRatio, (viewer->core.viewport[3] - coord[1])/m_PixelRatio),
  305. ImGui::GetColorU32(ImVec4(0, 0, 10, 255)),
  306. &text[0], &text[0] + text.size());
  307. }
  308. IGL_INLINE float ImGuiMenu::pixel_ratio()
  309. {
  310. // Computes pixel ratio for hidpi devices
  311. int buf_size[2];
  312. int win_size[2];
  313. GLFWwindow* window = glfwGetCurrentContext();
  314. glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
  315. glfwGetWindowSize(window, &win_size[0], &win_size[1]);
  316. return (float) buf_size[0] / (float) win_size[0];
  317. }
  318. IGL_INLINE float ImGuiMenu::hidpi_scaling()
  319. {
  320. // Computes scaling factor for hidpi devices
  321. float xscale, yscale;
  322. GLFWwindow* window = glfwGetCurrentContext();
  323. glfwGetWindowContentScale(window, &xscale, &yscale);
  324. return 0.5 * (xscale + yscale);
  325. }
  326. } // end namespace
  327. } // end namespace
  328. } // end namespace
  329. } // end namespace