main_impl.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #include "main_impl.h"
  2. #include "core/object_manager.h"
  3. #include "apps/app_selector/app_selector.h"
  4. #include <boost/asio/io_context.hpp>
  5. #include <boost/asio/post.hpp>
  6. #include <boost/asio/steady_timer.hpp>
  7. #include <glad/gl.h>
  8. #include <GLFW/glfw3.h>
  9. #include <imgui.h>
  10. #include <imgui_impl_glfw.h>
  11. #include <imgui_impl_opengl3.h>
  12. // make glad happy
  13. #include "core/imgui_utility.hpp"
  14. using boost::asio::io_context;
  15. using boost::asio::post;
  16. using boost::asio::steady_timer;
  17. using boost::system::error_code;
  18. CUcontext cuda_ctx = nullptr;
  19. GLFWwindow *window = nullptr;
  20. smart_cuda_stream *default_cuda_stream = nullptr;
  21. io_context *main_ctx;
  22. object_manager *main_ob;
  23. using cleanup_list_type =
  24. std::vector<cleanup_func_type>;
  25. cleanup_list_type cleanup_list;
  26. //event_timer perf_timer; // performance timer
  27. std::unique_ptr<steady_timer> ui_timer;
  28. std::chrono::milliseconds ui_interval;
  29. std::unique_ptr<app_base> app;
  30. bool hide_app_ui = false;
  31. bool hide_debug_ui = true;
  32. bool show_demo = false;
  33. // display config
  34. bool full_screen = false;
  35. int chose_monitor = 0;
  36. struct {
  37. int x_pos, y_pos;
  38. int width, height;
  39. } win_info; // windowed mode info
  40. void init_cuda() {
  41. cuInit(0);
  42. auto cuda_dev = CUdevice();
  43. CUDA_API_CHECK(cuDeviceGet(&cuda_dev, 0)); // TODO: select device
  44. CUDA_API_CHECK(cuCtxCreate(&cuda_ctx, CU_CTX_SCHED_AUTO, cuda_dev));
  45. default_cuda_stream = new smart_cuda_stream();
  46. std::atexit([] { // elegant cleanup
  47. cuCtxDestroy(cuda_ctx);
  48. });
  49. }
  50. void init_window() {
  51. // set GLFW error handler
  52. glfwSetErrorCallback([](int error, const char *desc) {
  53. SPDLOG_ERROR("GLFW error: code = {}, description = {}", error, desc);
  54. });
  55. // create main window
  56. auto ret = glfwInit();
  57. assert(ret == GLFW_TRUE);
  58. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  59. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
  60. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  61. // TODO: select width and height
  62. window = glfwCreateWindow(800, 600, "An not simple platform for visual navigation", nullptr, nullptr);
  63. assert(window != nullptr);
  64. glfwMakeContextCurrent(window);
  65. glfwSwapInterval(0);
  66. // load opengl functions
  67. auto version = gladLoadGL(glfwGetProcAddress);
  68. assert(version > 0);
  69. SPDLOG_INFO("Loaded OpenGL {}.{}", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
  70. // enable color blending
  71. glEnable(GL_BLEND);
  72. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  73. #ifndef NDEBUG
  74. // log opengl error
  75. glEnable(GL_DEBUG_OUTPUT);
  76. glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity,
  77. GLsizei length, const GLchar *message, const void *user_data) {
  78. if (type == GL_DEBUG_TYPE_ERROR) {
  79. SPDLOG_ERROR("OpenGL error: type = {}, severity = {}, message = {}", type, severity, message);
  80. assert(false);
  81. }
  82. }, nullptr);
  83. #endif
  84. // setup imgui context
  85. IMGUI_CHECKVERSION();
  86. ImGui::CreateContext();
  87. auto io = ImGui::GetIO();
  88. io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
  89. ImGui::StyleColorsDark();
  90. ImGui_ImplGlfw_InitForOpenGL(window, true);
  91. ImGui_ImplOpenGL3_Init();
  92. // elegant cleanup
  93. std::atexit([] {
  94. ImGui_ImplOpenGL3_Shutdown();
  95. ImGui_ImplGlfw_Shutdown();
  96. ImGui::DestroyContext();
  97. glfwDestroyWindow(window);
  98. glfwTerminate();
  99. });
  100. }
  101. void ui_timer_func(error_code ec) {
  102. if (ec == boost::asio::error::operation_aborted) return;
  103. assert(ec == error_code());
  104. show_ui();
  105. ui_timer->expires_after(ui_interval);
  106. ui_timer->async_wait(ui_timer_func);
  107. }
  108. void init_all() {
  109. init_cuda();
  110. init_window();
  111. main_ctx = new io_context();
  112. main_ob = new object_manager({.ctx = main_ctx});
  113. auto app_conf = app_selector::create_config();
  114. app_conf.asio_ctx = main_ctx;
  115. app_conf.cuda_ctx = &cuda_ctx;
  116. app_conf.app_ptr = &app;
  117. app = std::make_unique<app_selector>(app_conf);
  118. glfwSetWindowTitle(window, app->window_name());
  119. ui_interval = std::chrono::milliseconds(33); // TODO: select refresh rate
  120. ui_timer = std::make_unique<steady_timer>(*main_ctx, ui_interval);
  121. ui_timer->async_wait(ui_timer_func);
  122. }
  123. void process_keys() {
  124. auto &io = ImGui::GetIO();
  125. if (io.WantCaptureKeyboard) return;
  126. if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_H)) { // Ctrl+H
  127. hide_app_ui ^= true;
  128. }
  129. if (io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_D)) { // Ctrl+D
  130. hide_debug_ui ^= true;
  131. }
  132. }
  133. void update_display() {
  134. auto win = glfwGetCurrentContext();
  135. if (!full_screen) {
  136. glfwSetWindowMonitor(win, nullptr, win_info.x_pos, win_info.y_pos,
  137. win_info.width, win_info.height, GLFW_DONT_CARE);
  138. } else {
  139. assert(full_screen);
  140. int monitor_num = 0;
  141. auto monitors = glfwGetMonitors(&monitor_num);
  142. assert(chose_monitor < monitor_num);
  143. auto monitor = monitors[chose_monitor];
  144. auto mode = glfwGetVideoMode(monitor);
  145. glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
  146. }
  147. }
  148. void recorde_window_info() {
  149. auto win = glfwGetCurrentContext();
  150. glfwGetWindowPos(win, &win_info.x_pos, &win_info.y_pos);
  151. glfwGetWindowSize(win, &win_info.width, &win_info.height);
  152. }
  153. void show_display_config() {
  154. // display mode
  155. if (ImGui::RadioButton("Windowed", !full_screen)) {
  156. if (full_screen) {
  157. full_screen = false;
  158. update_display();
  159. }
  160. }
  161. ImGui::SameLine();
  162. if (ImGui::RadioButton("Full Screen", full_screen)) {
  163. if (!full_screen) {
  164. recorde_window_info();
  165. full_screen = true;
  166. update_display();
  167. }
  168. }
  169. if (full_screen) {
  170. int monitor_count;
  171. auto monitors = glfwGetMonitors(&monitor_count);
  172. if (chose_monitor >= monitor_count) {
  173. chose_monitor = 0;
  174. }
  175. auto monitor_name_preview = glfwGetMonitorName(monitors[chose_monitor]);
  176. if (ImGui::BeginCombo("Monitor", monitor_name_preview)) { // let user select monitors
  177. for (int k = 0; k < monitor_count; ++k) {
  178. auto is_selected = (chose_monitor == k);
  179. auto monitor_name = fmt::format("{} - {}", k, glfwGetMonitorName(monitors[k]));
  180. if (ImGui::Selectable(monitor_name.c_str(), is_selected)) {
  181. if (chose_monitor != k) {
  182. chose_monitor = k;
  183. update_display();
  184. }
  185. }
  186. if (is_selected) {
  187. ImGui::SetItemDefaultFocus();
  188. }
  189. }
  190. ImGui::EndCombo();
  191. }
  192. }
  193. }
  194. void show_debug_ui() {
  195. if (ImGui::Begin("Debug")) {
  196. ImGui::SeparatorText("Display Config");
  197. show_display_config();
  198. ImGui::SeparatorText("Miscellaneous");
  199. ImGui::Checkbox("Show Demo", &show_demo);
  200. }
  201. ImGui::End();
  202. }
  203. void show_ui() {
  204. glfwPollEvents();
  205. ImGui_ImplOpenGL3_NewFrame();
  206. ImGui_ImplGlfw_NewFrame();
  207. ImGui::NewFrame();
  208. if (glfwWindowShouldClose(window)) {
  209. ui_timer->cancel();
  210. main_ctx->stop();
  211. return;
  212. }
  213. process_keys();
  214. assert(app != nullptr);
  215. if (!hide_app_ui) {
  216. app->show_ui();
  217. }
  218. if (!hide_debug_ui) {
  219. show_debug_ui();
  220. }
  221. if (show_demo) {
  222. ImGui::ShowDemoWindow();
  223. }
  224. cv::Size frame_size;
  225. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  226. glfwGetFramebufferSize(window, &frame_size.width, &frame_size.height);
  227. glViewport(0, 0, frame_size.width, frame_size.height);
  228. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  229. app->render_background();
  230. ImGui::Render();
  231. ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
  232. glfwSwapBuffers(window);
  233. }
  234. void register_cleanup_func(cleanup_func_type func) {
  235. cleanup_list.push_back(func);
  236. }
  237. void cleanup() {
  238. app = nullptr;
  239. ui_timer = nullptr;
  240. // custom cleanup funcs
  241. for (auto func: cleanup_list) {
  242. func();
  243. }
  244. delete main_ob;
  245. delete main_ctx;
  246. }