diff --git a/ext/imgui.cmake b/ext/imgui.cmake new file mode 100644 index 0000000..815b288 --- /dev/null +++ b/ext/imgui.cmake @@ -0,0 +1,31 @@ +include(FetchContent) + +FetchContent_Declare( + imgui + GIT_REPOSITORY https://github.com/ocornut/imgui + GIT_TAG v1.86 + GIT_PROGRESS TRUE +) + +FetchContent_GetProperties(imgui) +if (NOT ${imgui}_POPULATED) + FetchContent_MakeAvailable(imgui) + + add_library( + imgui + ${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.h + ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.h + ${imgui_SOURCE_DIR}/imgui.cpp + ${imgui_SOURCE_DIR}/imgui.h + ${imgui_SOURCE_DIR}/imgui_demo.cpp + ${imgui_SOURCE_DIR}/imgui_draw.cpp + ${imgui_SOURCE_DIR}/imgui_tables.cpp + ${imgui_SOURCE_DIR}/imgui_widgets.cpp + ) + + target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR}) + target_link_libraries(imgui PRIVATE glfw) +endif () + diff --git a/vis/CMakeLists.txt b/vis/CMakeLists.txt index 2a7cf09..2d18e08 100644 --- a/vis/CMakeLists.txt +++ b/vis/CMakeLists.txt @@ -14,6 +14,6 @@ add_executable(vis target_include_directories(vis PRIVATE include) target_link_libraries(vis PRIVATE tc shaders - glad eigen glfw yaml-cpp fmt EnTT + glad eigen glfw yaml-cpp fmt EnTT imgui ) add_dependencies(vis presets) diff --git a/vis/src/main.cpp b/vis/src/main.cpp index 8da92f1..305a598 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -1,8 +1,13 @@ #include #include + #include #include +#include +#include +#include + #include #include "util.hpp" @@ -37,17 +42,16 @@ struct Matrices { }; struct State { - float time; - float time_delta; - - float st; - int dimension; + float time = 0; + + Eigen::Matrix4f view = Eigen::Matrix4f::Identity(); + entt::registry registry; }; -Matrices build(GLFWwindow* window, State &state) { +Matrices build(GLFWwindow* window, State &state, ImGuiContext* ctx) { int width, height; glfwGetFramebufferSize(window, &width, &height); @@ -56,50 +60,63 @@ Matrices build(GLFWwindow* window, State &state) { auto pwidth = aspect * pheight; Eigen::Matrix4f proj = orthographic(-pwidth, pwidth, -pheight, pheight, -10.0f, 10.0f); - if (!glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) { - state.st += state.time_delta / 8; + auto &io = ImGui::GetIO(); + + if (io.MouseDown[0] && !io.WantCaptureMouse) { + Eigen::Vector4f src{0, 0, 1, 0}; + Eigen::Vector4f dst{io.MouseDelta.x, -io.MouseDelta.y, 300, 0}; + dst.normalize(); + + auto rotate = rotor(src, dst); + state.view = rotate * state.view; } - static bool init = false; - static Eigen::Vector2d last; - Eigen::Vector2d pos; - - glfwGetCursorPos(window, &pos.x(), &pos.y()); - if (!init) { - last = pos; - init = true; - } - Eigen::Vector2d dpos = pos - last; - last = pos; - - static Eigen::Matrix4f view = Eigen::Matrix4f::Identity(); - - if (state.dimension < 4) { - view *= rot<4>(2, 3, M_PI_2f32 + 0.01f); - } - - if (glfwGetMouseButton(window, 0)) { - float scale = 0.005; - auto rotate = rotor( - Eigen::Vector4f{0, 0, 1, 0}, - Eigen::Vector4f{ - dpos.x() * scale, - -dpos.y() * scale, - 1, 0 - }.normalized() - ); - view = rotate * view; - } - - return Matrices(proj, view); + return Matrices(proj, state.view); } -void run(const std::string &config_file, GLFWwindow* window) { -#ifndef NDEBUG - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(log_gl_debug_callback, nullptr); -#endif +void show_overlay(State &state) { + static std::string gl_vendor = (const char*) glGetString(GL_VENDOR); + static std::string gl_renderer = (const char*) glGetString(GL_RENDERER); + static std::string gl_version = (const char*) glGetString(GL_VERSION); + static std::string glsl_version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); + ImGuiWindowFlags window_flags = + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_NoBringToFrontOnFocus | + ImGuiWindowFlags_NoMove; + + ImGuiStyle &style = ImGui::GetStyle(); + const auto PAD = style.DisplaySafeAreaPadding; + auto window_pos = PAD; + + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always); + ImGui::SetNextWindowBgAlpha(0.35f * style.Alpha); + ImGui::SetNextWindowCollapsed(true, ImGuiCond_Appearing); + ImGui::Begin("Graphics Information", nullptr, window_flags); + ImGui::Text("GL Vendor | %s", gl_vendor.c_str()); + ImGui::Text("GL Renderer | %s", gl_renderer.c_str()); + ImGui::Text("GL Version | %s", gl_version.c_str()); + ImGui::Text("GLSL Version | %s", glsl_version.c_str()); + + auto v2 = ImGui::GetWindowSize(); + window_pos.y += v2.y + PAD.y; + ImGui::End(); +} + +void set_style() { + ImGui::StyleColorsDark(); + + ImGuiStyle &style = ImGui::GetStyle(); + style.WindowRounding = 4; + style.FrameRounding = 2; + style.DisplaySafeAreaPadding.x = 10; + style.DisplaySafeAreaPadding.y = 10; +} + +void run(GLFWwindow* window, ImGuiContext* ctx) { if (glfwRawMouseMotionSupported()) { glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); } @@ -124,10 +141,13 @@ void run(const std::string &config_file, GLFWwindow* window) { tc::schlafli({5, 3, 3, 2}), vec5{0.80, 0.09, 0.09, 0.09, 0.09}, vec3{0.90, 0.90, 0.90}, - std::vector>{{0, 1, 2}, - {0, 3, 4}, - {1, 3, 4}, - {2, 3, 4}} + std::vector>{ + {0, 1, 2}, + + {0, 3, 4}, + {1, 3, 4}, + {2, 3, 4}, + } ); registry.emplace(entity); @@ -137,9 +157,20 @@ void run(const std::string &config_file, GLFWwindow* window) { glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo); while (!glfwWindowShouldClose(window)) { - auto time = (float) glfwGetTime(); - state.time_delta = state.time - time; - state.time = time; + glfwPollEvents(); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + + auto io = ImGui::GetIO(); + if (io.KeysDown[GLFW_KEY_ESCAPE]) { + glfwSetWindowShouldClose(window, true); + continue; + } + + ImGui::NewFrame(); + show_overlay(state); + ImGui::Render(); int width, height; glfwGetFramebufferSize(window, &width, &height); @@ -147,37 +178,45 @@ void run(const std::string &config_file, GLFWwindow* window) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ubo.put(build(window, state)); + ubo.put(build(window, state, ctx)); { auto &tform = registry.get(entity).tform; + if (!io.KeysDown[GLFW_KEY_SPACE]) { + float speed = 1.0 / 8.0; + if (io.KeysDown[GLFW_KEY_LEFT_SHIFT] | io.KeysDown[GLFW_KEY_RIGHT_SHIFT]) { + speed /= 4; + } + state.time += io.DeltaTime * speed; + } + tform.linear().setIdentity(); if (state.dimension > 1) { - tform.linear() *= rot<4>(0, 1, state.st * .40f); + tform.linear() *= rot<4>(0, 1, state.time * .40f); } if (state.dimension > 2) { - tform.linear() *= rot<4>(0, 2, state.st * .20f); - tform.linear() *= rot<4>(1, 2, state.st * .50f); + tform.linear() *= rot<4>(0, 2, state.time * .20f); + tform.linear() *= rot<4>(1, 2, state.time * .50f); } if (state.dimension > 3) { - tform.linear() *= rot<4>(0, 3, state.st * 1.30f); - tform.linear() *= rot<4>(1, 3, state.st * .25f); - tform.linear() *= rot<4>(2, 3, state.st * 1.42f); + tform.linear() *= rot<4>(0, 3, state.time * 1.30f); + tform.linear() *= rot<4>(1, 3, state.time * .25f); + tform.linear() *= rot<4>(2, 3, state.time * 1.42f); } - tform.translation().w() = std::sin(time * 0.3f) * 1.0f; + tform.translation().w() = std::sin(state.time * 1.4) * 1.0; } vis::upload_ubo(registry); renderer(registry); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + glfwSwapInterval(2); glfwSwapBuffers(window); - - glfwPollEvents(); } } @@ -206,16 +245,34 @@ int main(int argc, char* argv[]) { glfwMakeContextCurrent(window); gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); glfwSwapInterval(1); - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - std::cout << utilInfo(); +#ifndef NDEBUG + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(log_gl_debug_callback, nullptr); +#endif - std::string config_file = "presets/default.yaml"; - if (argc > 1) config_file = std::string(argv[1]); + IMGUI_CHECKVERSION(); + auto* context = ImGui::CreateContext(); + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 130"); - run(config_file, window); + set_style(); + int exit_code = EXIT_SUCCESS; + + try { + run(window, context); + } catch (const std::exception &e) { + std::cerr << e.what() << std::endl; + exit_code = EXIT_FAILURE; + } + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); glfwTerminate(); - return EXIT_SUCCESS; + + return exit_code; }