From 5dd4da0e30e644f5328cd7cf249091367d5bd620 Mon Sep 17 00:00:00 2001 From: timerix Date: Fri, 31 Mar 2023 20:27:04 +0600 Subject: [PATCH] optimized main loop and split it into parts --- imgui | 2 +- src/gui/demo_ui.cpp | 45 +++++++++ src/gui/gui.h | 2 +- src/gui/gui_internal.hpp | 7 ++ src/gui/main_window.cpp | 194 ++++++++++++++++++++------------------- src/main.c | 2 +- 6 files changed, 153 insertions(+), 99 deletions(-) create mode 100644 src/gui/demo_ui.cpp diff --git a/imgui b/imgui index 3e08a7e..9e12957 160000 --- a/imgui +++ b/imgui @@ -1 +1 @@ -Subproject commit 3e08a7e76e7e275e90d22d9081c01e0515d187b0 +Subproject commit 9e129571c74f68a954916a3d857a43698df3a51f diff --git a/src/gui/demo_ui.cpp b/src/gui/demo_ui.cpp new file mode 100644 index 0000000..5b95393 --- /dev/null +++ b/src/gui/demo_ui.cpp @@ -0,0 +1,45 @@ +#include "gui_internal.hpp" + +bool show_demo_window = true; +bool show_another_window = false; + +Maybe demo_ui_draw(ImGuiIO& io){ + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + return MaybeNull; +} diff --git a/src/gui/gui.h b/src/gui/gui.h index 95657c8..c4a0f60 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -6,7 +6,7 @@ extern "C" { #include "../../kerep/src/base/base.h" -Maybe main_window_open(); +Maybe main_window_open(const char* window_title); Maybe main_window_loop_start(); Maybe main_window_close(); diff --git a/src/gui/gui_internal.hpp b/src/gui/gui_internal.hpp index b94f673..d2fdc50 100644 --- a/src/gui/gui_internal.hpp +++ b/src/gui/gui_internal.hpp @@ -6,3 +6,10 @@ #include "../../imgui/imgui.h" #include "../../imgui/backends/imgui_impl_sdl2.h" #include "../../imgui/backends/imgui_impl_opengl3.h" + +const u8 frame_rate_max=60; // frames per second +extern ImVec4 clear_color; // background color for main window + +/// @brief frees all allocated resources +void main_window_destroy(); +Maybe demo_ui_draw(ImGuiIO&); diff --git a/src/gui/main_window.cpp b/src/gui/main_window.cpp index 6ef883a..9ca4cc1 100644 --- a/src/gui/main_window.cpp +++ b/src/gui/main_window.cpp @@ -1,6 +1,6 @@ #include "gui_internal.hpp" -const char* window_title="GraphC"; +ImVec4 clear_color = RGBAHexToF(35,35,50,255); bool loop_running=false; SDL_Window* sdl_window; SDL_GLContext gl_context; @@ -11,8 +11,9 @@ SDL_GLContext gl_context; SDL_ClearError(); \ } #define SDL_TRY_ZERO(FUNC_CALL) if(FUNC_CALL != 0) SDL_ERROR_SAFETHROW(); +#define SDL_TRY_ONE(FUNC_CALL) if(FUNC_CALL != 1) SDL_ERROR_SAFETHROW(); -Maybe main_window_open(){ +Maybe main_window_open(const char* window_title){ SDL_TRY_ZERO(SDL_Init(SDL_INIT_VIDEO)); // GL 3.0 + GLSL 130 const char* glsl_version = "#version 130"; @@ -46,8 +47,11 @@ Maybe main_window_open(){ io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows - io.ConfigViewportsNoDecoration=false; - + io.ConfigDockingTransparentPayload = true; + io.ConfigInputTextCursorBlink = false; + io.ConfigViewportsNoTaskBarIcon = true; + io.ConfigWindowsMoveFromTitleBarOnly = true; + // Setup Dear ImGui style ImGui::StyleColorsDark(); @@ -68,109 +72,99 @@ Maybe main_window_open(){ return MaybeNull; } +// Wait, poll and handle events (inputs, window resize, etc.) +// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +Maybe poll_events(bool& frame_needs_update, bool wait){ + SDL_Event event; + if(wait){ + // waits for first event in cpu-efficient way + SDL_TRY_ONE(SDL_WaitEvent(&event)); + } + // doesnt wait for event + else if(!SDL_PollEvent(&event)) + return MaybeNull; + + do { + frame_needs_update|=ImGui_ImplSDL2_ProcessEvent(&event); + switch(event.type){ + case SDL_QUIT: { + try_cpp(main_window_close(),_9914,;); + break; + } + case SDL_WINDOWEVENT: { + if(event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(sdl_window)){ + try_cpp(main_window_close(),_9915,;); + } + break; + } + } + } while (SDL_PollEvent(&event)); // if there are more events, handles them + return MaybeNull; +} + +Maybe draw_frame(){ + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + ImGuiIO& io = ImGui::GetIO(); + + // Draw UI + try_cpp(demo_ui_draw(io), _5218, ;); + + // Rendering + ImGui::Render(); + glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); + glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + // Update and Render additional Platform Windows + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); + } + + SDL_GL_SwapWindow(sdl_window); + + return MaybeNull; +} + Maybe main_window_loop_start(){ if(loop_running) safethrow_msg("loop is already running",;); - loop_running=true; - // Our state - bool show_demo_window = true; - bool show_another_window = false; - ImVec4 clear_color = RGBAHexToF(35,35,50,255); + // draw first frame + try_cpp(draw_frame(),_2175,;); // main loop + loop_running=true; while(loop_running){ - // Poll and handle events (inputs, window resize, etc.) - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. - // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. - // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. - // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. - SDL_Event event; - while (SDL_PollEvent(&event)) - { - ImGui_ImplSDL2_ProcessEvent(&event); - if (event.type == SDL_QUIT){ - try_cpp(main_window_close(),_9914,;); - } - if (event.type==SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(sdl_window)){ - try_cpp(main_window_close(),_9915,;); - } - } + bool frame_needs_update=false; + // waits for events + try_cpp(poll_events(frame_needs_update, true),_55415,;); - // Start the Dear ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); + if(!frame_needs_update){ + // skips frame rendering if user didn't interacted with anything + u32 frame_delay_ms=1000/frame_rate_max; + SDL_Delay(frame_delay_ms); + continue; + } - ImGuiIO& io = ImGui::GetIO(); (void)io; - - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::End(); - } - - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } - - // Rendering - ImGui::Render(); - glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); - glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - // Update and Render additional Platform Windows - // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. - // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); - SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - SDL_GL_MakeCurrent(backup_current_window, backup_current_context); - } - - SDL_GL_SwapWindow(sdl_window); + try_cpp(draw_frame(),_2175,;); } // Cleanup - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - SDL_GL_DeleteContext(gl_context); - SDL_DestroyWindow(sdl_window); - SDL_Quit(); - + main_window_destroy(); return MaybeNull; } @@ -178,6 +172,14 @@ Maybe main_window_close(){ if(!loop_running) return MaybeNull; loop_running=false; - return MaybeNull; } + +void main_window_destroy(){ + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + SDL_GL_DeleteContext(gl_context); + SDL_DestroyWindow(sdl_window); + SDL_Quit(); +} diff --git a/src/main.c b/src/main.c index 6c73838..72e481e 100644 --- a/src/main.c +++ b/src/main.c @@ -19,7 +19,7 @@ int main(const int argc, const char* const* argv){ kprintf(" %s", argv[i]); kprintf("\n"); - tryLast(main_window_open(),_1); + tryLast(main_window_open("GraphC"),_1); tryLast(main_window_loop_start(),_2); tryLast(main_window_close(),_3);