From 0e5f1e5b5fb54d6630f196f0aed84f57695c0515 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 20 Dec 2018 20:30:22 +0100 Subject: [PATCH 1/8] cmake+imgui: add imgui submodule --- .gitmodules | 3 ++ cmake_options.cmake | 1 + external/CMakeLists.txt | 4 +++ external/imgui/CMakeLists.txt | 58 +++++++++++++++++++++++++++++++++++ external/imgui/imgui | 1 + external/imgui/rw_imconfig.h | 9 ++++++ 6 files changed, 76 insertions(+) create mode 100644 external/imgui/CMakeLists.txt create mode 160000 external/imgui/imgui create mode 100644 external/imgui/rw_imconfig.h diff --git a/.gitmodules b/.gitmodules index b044f920..cfc1cab8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "external/microprofile/microprofile"] path = external/microprofile/microprofile url = https://github.com/jonasmr/microprofile.git +[submodule "imgui"] + path = external/imgui/imgui + url = https://github.com/ocornut/imgui.git diff --git a/cmake_options.cmake b/cmake_options.cmake index d0d10cb0..b6362cf1 100644 --- a/cmake_options.cmake +++ b/cmake_options.cmake @@ -6,6 +6,7 @@ option(BUILD_VIEWER "Build GUI data viewer") option(ENABLE_SCRIPT_DEBUG "Enable verbose script execution") option(ENABLE_PROFILING "Enable detailed profiling metrics") +option(ENABLE_IMGUI "Enable imgui plugin") option(TEST_DATA "Enable tests that require game data") diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index de3bbe45..9c4fa96e 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,3 +1,7 @@ if(ENABLE_PROFILING) add_subdirectory(microprofile) endif() + +if(ENABLE_IMGUI) + add_subdirectory(imgui) +endif() diff --git a/external/imgui/CMakeLists.txt b/external/imgui/CMakeLists.txt new file mode 100644 index 00000000..700dc127 --- /dev/null +++ b/external/imgui/CMakeLists.txt @@ -0,0 +1,58 @@ +add_library(imgui EXCLUDE_FROM_ALL + rw_imconfig.h + imgui/imgui.h + imgui/imgui.cpp + imgui/imgui_demo.cpp + imgui/imgui_draw.cpp + imgui/imgui_internal.h + imgui/imgui_widgets.cpp + imgui/imstb_rectpack.h + imgui/imstb_textedit.h + imgui/imstb_truetype.h +) + +target_include_directories(imgui SYSTEM + PUBLIC + "${CMAKE_CURRENT_LIST_DIR}/imgui" +) + +target_compile_definitions(imgui + PUBLIC + IMGUI_USER_CONFIG="${CMAKE_CURRENT_SOURCE_DIR}/rw_imconfig.h" +) + +add_library(imgui::core ALIAS imgui) + +openrw_target_apply_options( + TARGET imgui +) + +add_library(imgui_sdl_gl3 EXCLUDE_FROM_ALL + imgui/examples/imgui_impl_opengl3.h + imgui/examples/imgui_impl_opengl3.cpp + imgui/examples/imgui_impl_sdl.h + imgui/examples/imgui_impl_sdl.cpp +) + +target_include_directories(imgui_sdl_gl3 SYSTEM + PUBLIC + "${CMAKE_CURRENT_LIST_DIR}/imgui/examples" +) + +target_link_libraries(imgui_sdl_gl3 + PUBLIC + imgui::core + SDL2::SDL2 +) + +# FIXME: extract gl loader to target + add property to get header +target_compile_definitions(imgui_sdl_gl3 + PRIVATE + "IMGUI_IMPL_OPENGL_LOADER_CUSTOM=\"${OpenRW_SOURCE_DIR}/rwcore/gl/gl_core_3_3.h\"" +) + +add_library(imgui::sdl_gl3 ALIAS imgui_sdl_gl3) + +openrw_target_apply_options( + TARGET imgui_sdl_gl3 +) diff --git a/external/imgui/imgui b/external/imgui/imgui new file mode 160000 index 00000000..801645d3 --- /dev/null +++ b/external/imgui/imgui @@ -0,0 +1 @@ +Subproject commit 801645d35092c8da0eeabe71d7c1997c47aa3648 diff --git a/external/imgui/rw_imconfig.h b/external/imgui/rw_imconfig.h new file mode 100644 index 00000000..f6d6482d --- /dev/null +++ b/external/imgui/rw_imconfig.h @@ -0,0 +1,9 @@ +#ifndef RW_IMCONFIG_H +#define RW_IMCONFIG_H + +// Disable imgui assertions when not in debug mode +#ifndef RW_DEBUG +#define IM_ASSERT(MSG) //FIXME(madebr): remove comment +#endif + +#endif // RW_IMCONFIG_H From e77a7caf7467dd9f547732b50cb875f068886a6d Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 20 Dec 2018 20:31:14 +0100 Subject: [PATCH 2/8] rwgame: add imgui demo window --- rwgame/CMakeLists.txt | 15 ++++ rwgame/GameBase.cpp | 2 +- rwgame/GameWindow.hpp | 7 +- rwgame/RWGame.cpp | 12 ++- rwgame/RWGame.hpp | 3 + rwgame/RWImGui.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++ rwgame/RWImGui.hpp | 21 +++++ 7 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 rwgame/RWImGui.cpp create mode 100644 rwgame/RWImGui.hpp diff --git a/rwgame/CMakeLists.txt b/rwgame/CMakeLists.txt index 2d555a8b..3996ef0a 100644 --- a/rwgame/CMakeLists.txt +++ b/rwgame/CMakeLists.txt @@ -15,6 +15,9 @@ add_library(librwgame STATIC GameWindow.hpp GameWindow.cpp + RWImGui.cpp + RWImGui.hpp + HUDDrawer.hpp HUDDrawer.cpp MenuSystem.hpp @@ -68,6 +71,18 @@ target_link_libraries(librwgame SDL2::SDL2 ) +if(ENABLE_IMGUI) + target_compile_definitions(librwgame + PUBLIC + RW_IMGUI + ) + + target_link_libraries(librwgame + PUBLIC + imgui::sdl_gl3 + ) +endif() + add_executable(rwgame main.cpp ) diff --git a/rwgame/GameBase.cpp b/rwgame/GameBase.cpp index c827d32d..1d73f661 100644 --- a/rwgame/GameBase.cpp +++ b/rwgame/GameBase.cpp @@ -20,7 +20,7 @@ GameBase::GameBase(Logger &inlog, const std::optional &args) : bool fullscreen = config.fullscreen(); size_t w = config.width(), h = config.height(); - if (SDL_Init(SDL_INIT_VIDEO) < 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) throw std::runtime_error("Failed to initialize SDL2!"); window.create(kWindowTitle + " [" + kBuildStr + "]", w, h, fullscreen); diff --git a/rwgame/GameWindow.hpp b/rwgame/GameWindow.hpp index 7d69d852..800a7ff0 100644 --- a/rwgame/GameWindow.hpp +++ b/rwgame/GameWindow.hpp @@ -5,8 +5,9 @@ #include #include - #include +#include +#include class GameWindow { SDL_Window* window = nullptr; @@ -30,6 +31,10 @@ public: bool isOpen() const { return !!window; } + + std::tuple getSDLContext() { + return std::make_tuple(window, glcontext); + } }; #endif diff --git a/rwgame/RWGame.cpp b/rwgame/RWGame.cpp index bbfed79f..7af0232a 100644 --- a/rwgame/RWGame.cpp +++ b/rwgame/RWGame.cpp @@ -2,6 +2,7 @@ #include +#include "RWImGui.hpp" #include "GameInput.hpp" #include "State.hpp" #include "StateManager.hpp" @@ -28,7 +29,6 @@ #include #include #include -#include #ifdef _MSC_VER #pragma warning(disable : 4305 5033) @@ -54,7 +54,8 @@ constexpr float kMaxPhysicsSubSteps = 2; RWGame::RWGame(Logger& log, const std::optional &args) : GameBase(log, args) , data(&log, config.gamedataPath()) - , renderer(&log, &data) { + , renderer(&log, &data) + , imgui(*this) { RW_PROFILE_THREAD("Main"); RW_TIMELINE_ENTER("Startup", MP_YELLOW); @@ -76,6 +77,8 @@ RWGame::RWGame(Logger& log, const std::optional &args) config.gamedataPath()); } + imgui.init(); + data.load(); for (const auto& [specialModel, fileName, name] : kSpecialModels) { @@ -480,6 +483,9 @@ bool RWGame::updateInput() { RW_PROFILE_SCOPE(__func__); SDL_Event event; while (SDL_PollEvent(&event)) { + if (imgui.process_event(event)) { + continue; + } switch (event.type) { case SDL_QUIT: return false; @@ -669,6 +675,8 @@ void RWGame::render(float alpha, float time) { RW_PROFILE_SCOPE("state"); stateManager.draw(renderer); } + + imgui.tick(); } void RWGame::renderDebugView(float time, ViewCamera &viewCam) { diff --git a/rwgame/RWGame.hpp b/rwgame/RWGame.hpp index 965a02ff..d8910f50 100644 --- a/rwgame/RWGame.hpp +++ b/rwgame/RWGame.hpp @@ -3,6 +3,8 @@ #include "GameBase.hpp" #include "HUDDrawer.hpp" +#include "RWConfig.hpp" +#include "RWImGui.hpp" #include "StateManager.hpp" #include "game.hpp" @@ -22,6 +24,7 @@ class RWGame final : public GameBase { GameData data; GameRenderer renderer; + RWImGui imgui; DebugDraw debug; GameState state; HUDDrawer hudDrawer{}; diff --git a/rwgame/RWImGui.cpp b/rwgame/RWImGui.cpp new file mode 100644 index 00000000..a9ac63d0 --- /dev/null +++ b/rwgame/RWImGui.cpp @@ -0,0 +1,177 @@ +#include "RWImGui.hpp" + +#ifdef RW_IMGUI + +#include "RWGame.hpp" + +#include +#include +#include + +#include + +RWImGui::RWImGui(RWGame &game) + : _game(game) { +} + +RWImGui::~RWImGui() { + destroy(); +} + +void RWImGui::init() { + IMGUI_CHECKVERSION(); + _context = ImGui::CreateContext(); + + auto [window, context] = _game.getWindow().getSDLContext(); + + ImGui_ImplSDL2_InitForOpenGL(window, context); + ImGui_ImplOpenGL3_Init("#version 150"); +} + +void RWImGui::destroy() { + if (!_context) { + return; + } + ImGui::SetCurrentContext(_context); + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + _context = nullptr; +} + +bool RWImGui::process_event(SDL_Event &event) { + if (!_context) { + return false; + } + ImGui::SetCurrentContext(_context); + ImGui_ImplSDL2_ProcessEvent(&event); + auto& io = ImGui::GetIO(); + return io.WantCaptureMouse || io.WantCaptureKeyboard; +} + +void RWImGui::tick() { + if (!_context) { + return; + } + ImGui::SetCurrentContext(_context); + auto& io = ImGui::GetIO(); + + SDL_Window *window; + std::tie(window, std::ignore) = _game.getWindow().getSDLContext(); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(window); + ImGui::NewFrame(); + + static float f = 0.0f; + + ImGui::Begin("Hello, world!"); + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", static_cast(1000.0f / io.Framerate), static_cast(io.Framerate)); ImGui::End(); + + static bool show_demo_window = true; + if (show_demo_window) { + ImGui::ShowDemoWindow(&show_demo_window); + } + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +static ImGuiIO *g_io; + +static SDL_Window *g_sdl_window; +static SDL_GLContext g_sdl_gl_context; + + +void imgui_init(SDL_Window *sdl_window, SDL_GLContext sdl_gl_context) { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + g_io = &ImGui::GetIO(); + + g_sdl_window = sdl_window; + g_sdl_gl_context = sdl_gl_context; + + ImGui_ImplSDL2_InitForOpenGL(sdl_window, sdl_gl_context); + ImGui_ImplOpenGL3_Init("#version 150"); + +// ImGui::StyleColorsDark(); +// ImGui::StyleColorsClassic(); + ImGui::StyleColorsLight(); + + + // Build atlas + unsigned char* tex_pixels = NULL; + int tex_w, tex_h; + g_io->Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_w, &tex_h); +} + +void imgui_process_event(SDL_Event *event, bool *mouse, bool *keyboard) { + ImGui_ImplSDL2_ProcessEvent(event); + *mouse = g_io->WantCaptureMouse; + *keyboard = g_io->WantCaptureKeyboard; +} + +static bool show_demo_window = true; + +void imgui_tick() { + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(g_sdl_window); + ImGui::NewFrame(); + +// g_io->DisplaySize = ImVec2(1920, 1080); +// g_io->DeltaTime = 1.0f / 60.0f; + + static float f = 0.0f; + + ImGui::Begin("Hello, world!"); + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", static_cast(1000.0f / g_io->Framerate), static_cast(g_io->Framerate)); + ImGui::End(); + + if (show_demo_window) { + ImGui::ShowDemoWindow(&show_demo_window); + } + +// ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + ImGui::Render(); +// SDL_GL_MakeCurrent(g_sdl_window, g_sdl_gl_context); +// glViewport(0, 0, static_cast(g_io->DisplaySize.x), static_cast(g_io->DisplaySize.y)); +// glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); +// glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +// SDL_GL_SwapWindow(g_sdl_window); +} + +void imgui_destroy() { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + g_io = nullptr; + g_sdl_gl_context = nullptr; + g_sdl_window = nullptr; +} + +#else + +RWImGui::RWImGui(RWGame &game) + : _game(game) { +} + +RWImGui::~RWImGui() { + destroy(); +} + +RWImGui::init(SDL_Window *window, SDL_GLContext context) { +} + +RWImGui::destroy() { +} + +RWImGui::process_event(SDL_Event &event) { +} + +#endif diff --git a/rwgame/RWImGui.hpp b/rwgame/RWImGui.hpp new file mode 100644 index 00000000..cb87d08b --- /dev/null +++ b/rwgame/RWImGui.hpp @@ -0,0 +1,21 @@ +#ifndef RWGAME_RWIMGUI_HPP +#define RWGAME_RWIMGUI_HPP + +#include + +class RWGame; +struct ImGuiContext; + +class RWImGui { + RWGame &_game; + ImGuiContext *_context = nullptr; +public: + RWImGui(RWGame &game); + ~RWImGui(); + void init(); + void destroy(); + bool process_event(SDL_Event &event); + void tick(); +}; + +#endif // RWGAME_RWIMGUI_HPP From c54d9ed2e22345ea338238d0b2d11e85837b2045 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 24 Dec 2018 15:48:01 +0100 Subject: [PATCH 3/8] rwgame: fix font in LoadingState --- rwgame/states/LoadingState.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rwgame/states/LoadingState.cpp b/rwgame/states/LoadingState.cpp index ac87558f..2f8fc4a5 100644 --- a/rwgame/states/LoadingState.cpp +++ b/rwgame/states/LoadingState.cpp @@ -28,15 +28,13 @@ void LoadingState::handleEvent(const SDL_Event& e) { } void LoadingState::draw(GameRenderer& r) { - static auto kLoadingString = - GameStringUtil::fromString("Loading...", FONT_ARIAL); // Display some manner of loading screen. TextRenderer::TextInfo ti; - ti.text = kLoadingString; + ti.text = GameStringUtil::fromString("Loading...", FONT_ARIAL); auto size = r.getRenderer().getViewport(); ti.size = 25.f; ti.screenPosition = glm::vec2(50.f, size.y - ti.size - 50.f); - ti.font = FONT_PRICEDOWN; + ti.font = FONT_ARIAL; ti.baseColour = glm::u8vec3(255); r.text.renderText(ti); } From cf38b449c5c66cfda0252fe1cf74fa996ac4fa77 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 28 Dec 2018 00:53:05 +0100 Subject: [PATCH 4/8] imgui changes --- external/imgui/CMakeLists.txt | 5 +++ rwgame/RWImGui.cpp | 79 +---------------------------------- 2 files changed, 6 insertions(+), 78 deletions(-) diff --git a/external/imgui/CMakeLists.txt b/external/imgui/CMakeLists.txt index 700dc127..1befa8fd 100644 --- a/external/imgui/CMakeLists.txt +++ b/external/imgui/CMakeLists.txt @@ -21,6 +21,11 @@ target_compile_definitions(imgui IMGUI_USER_CONFIG="${CMAKE_CURRENT_SOURCE_DIR}/rw_imconfig.h" ) +target_link_libraries(imgui + PUBLIC + openrw::checks +) + add_library(imgui::core ALIAS imgui) openrw_target_apply_options( diff --git a/rwgame/RWImGui.cpp b/rwgame/RWImGui.cpp index a9ac63d0..d3affa05 100644 --- a/rwgame/RWImGui.cpp +++ b/rwgame/RWImGui.cpp @@ -56,8 +56,7 @@ void RWImGui::tick() { ImGui::SetCurrentContext(_context); auto& io = ImGui::GetIO(); - SDL_Window *window; - std::tie(window, std::ignore) = _game.getWindow().getSDLContext(); + auto [window, sdl_glcontext] = _game.getWindow().getSDLContext(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(window); @@ -79,82 +78,6 @@ void RWImGui::tick() { ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } -static ImGuiIO *g_io; - -static SDL_Window *g_sdl_window; -static SDL_GLContext g_sdl_gl_context; - - -void imgui_init(SDL_Window *sdl_window, SDL_GLContext sdl_gl_context) { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - g_io = &ImGui::GetIO(); - - g_sdl_window = sdl_window; - g_sdl_gl_context = sdl_gl_context; - - ImGui_ImplSDL2_InitForOpenGL(sdl_window, sdl_gl_context); - ImGui_ImplOpenGL3_Init("#version 150"); - -// ImGui::StyleColorsDark(); -// ImGui::StyleColorsClassic(); - ImGui::StyleColorsLight(); - - - // Build atlas - unsigned char* tex_pixels = NULL; - int tex_w, tex_h; - g_io->Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_w, &tex_h); -} - -void imgui_process_event(SDL_Event *event, bool *mouse, bool *keyboard) { - ImGui_ImplSDL2_ProcessEvent(event); - *mouse = g_io->WantCaptureMouse; - *keyboard = g_io->WantCaptureKeyboard; -} - -static bool show_demo_window = true; - -void imgui_tick() { - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplSDL2_NewFrame(g_sdl_window); - ImGui::NewFrame(); - -// g_io->DisplaySize = ImVec2(1920, 1080); -// g_io->DeltaTime = 1.0f / 60.0f; - - static float f = 0.0f; - - ImGui::Begin("Hello, world!"); - ImGui::Text("Hello, world!"); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", static_cast(1000.0f / g_io->Framerate), static_cast(g_io->Framerate)); - ImGui::End(); - - if (show_demo_window) { - ImGui::ShowDemoWindow(&show_demo_window); - } - -// ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - - ImGui::Render(); -// SDL_GL_MakeCurrent(g_sdl_window, g_sdl_gl_context); -// glViewport(0, 0, static_cast(g_io->DisplaySize.x), static_cast(g_io->DisplaySize.y)); -// glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); -// glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); -// SDL_GL_SwapWindow(g_sdl_window); -} - -void imgui_destroy() { - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - g_io = nullptr; - g_sdl_gl_context = nullptr; - g_sdl_window = nullptr; -} - #else RWImGui::RWImGui(RWGame &game) From 4202297e0e55681cfbb0beef9f9da47f1bfc8428 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Tue, 21 May 2019 20:04:55 +0100 Subject: [PATCH 5/8] Render debug view UI with ImGui --- rwengine/src/render/ViewCamera.hpp | 2 +- rwengine/src/render/ViewFrustum.cpp | 2 +- rwengine/src/render/ViewFrustum.hpp | 2 +- rwgame/RWGame.cpp | 156 ++-------------------------- rwgame/RWGame.hpp | 28 ++--- rwgame/RWImGui.cpp | 147 ++++++++++++++++++++++++-- rwgame/RWImGui.hpp | 6 +- 7 files changed, 168 insertions(+), 175 deletions(-) diff --git a/rwengine/src/render/ViewCamera.hpp b/rwengine/src/render/ViewCamera.hpp index d2cd5927..b112f4ee 100644 --- a/rwengine/src/render/ViewCamera.hpp +++ b/rwengine/src/render/ViewCamera.hpp @@ -19,7 +19,7 @@ public: , rotation(rot) { } - glm::mat4 getView() { + glm::mat4 getView() const { auto up = rotation * glm::vec3(0.f, 0.f, 1.f); return glm::lookAt(position, position + rotation * glm::vec3(1.f, 0.f, 0.f), up); diff --git a/rwengine/src/render/ViewFrustum.cpp b/rwengine/src/render/ViewFrustum.cpp index 135fd2a1..ab6366b5 100644 --- a/rwengine/src/render/ViewFrustum.cpp +++ b/rwengine/src/render/ViewFrustum.cpp @@ -3,7 +3,7 @@ #include #include -glm::mat4 ViewFrustum::projection() { +glm::mat4 ViewFrustum::projection() const { return glm::perspective(fov / aspectRatio, aspectRatio, near, far); } diff --git a/rwengine/src/render/ViewFrustum.hpp b/rwengine/src/render/ViewFrustum.hpp index 927a0133..f00cd184 100644 --- a/rwengine/src/render/ViewFrustum.hpp +++ b/rwengine/src/render/ViewFrustum.hpp @@ -27,7 +27,7 @@ public: : near(near), far(far), fov(fov), aspectRatio(aspect) { } - glm::mat4 projection(); + glm::mat4 projection() const; void update(const glm::mat4& proj); diff --git a/rwgame/RWGame.cpp b/rwgame/RWGame.cpp index 7af0232a..e2e539d7 100644 --- a/rwgame/RWGame.cpp +++ b/rwgame/RWGame.cpp @@ -483,7 +483,7 @@ bool RWGame::updateInput() { RW_PROFILE_SCOPE(__func__); SDL_Event event; while (SDL_PollEvent(&event)) { - if (imgui.process_event(event)) { + if (imgui.processEvent(event)) { continue; } switch (event.type) { @@ -634,10 +634,12 @@ void RWGame::tickObjects(float dt) const { void RWGame::render(float alpha, float time) { RW_PROFILE_SCOPEC(__func__, MP_CORNFLOWERBLUE); + RW_UNUSED(time); lastDraws = getRenderer().getRenderer().getDrawCount(); getRenderer().getRenderer().swap(); + imgui.startFrame(); // Update the camera if (!stateManager.states.empty()) { @@ -667,7 +669,7 @@ void RWGame::render(float alpha, float time) { renderer.getRenderer().popDebugGroup(); - renderDebugView(time, viewCam); + renderDebugView(); if (!world->isPaused()) hudDrawer.drawOnScreenText(world.get(), renderer); @@ -676,99 +678,25 @@ void RWGame::render(float alpha, float time) { stateManager.draw(renderer); } - imgui.tick(); + imgui.endFrame(viewCam); } -void RWGame::renderDebugView(float time, ViewCamera &viewCam) { +void RWGame::renderDebugView() { RW_PROFILE_SCOPE(__func__); switch (debugview_) { - case DebugViewMode::General: - renderDebugStats(time); - break; case DebugViewMode::Physics: world->dynamicsWorld->debugDrawWorld(); debug.flush(renderer); break; case DebugViewMode::Navigation: - renderDebugPaths(time); - break; - case DebugViewMode::Objects: - renderDebugObjects(time, viewCam); + renderDebugPaths(); break; default: break; } } -void RWGame::renderDebugStats(float time) { - // Turn time into milliseconds - float time_ms = time * 1000.f; - constexpr size_t average_every_frame = 15; - static float times[average_every_frame]; - static size_t times_index = 0; - static float time_average = 0; - times[times_index++] = time_ms; - if (times_index >= average_every_frame) { - times_index = 0; - time_average = 0; - - for (size_t i = 0; i < average_every_frame; ++i) { - time_average += times[i]; - } - time_average /= average_every_frame; - } - - std::stringstream ss; - ss << "FPS: " << (1000.f / time_average) << " (" << time_average << "ms)\n" - << "Frame: " << time_ms << "ms\n" - << "Draws/Culls/Textures/Buffers: " << lastDraws << "/" - << renderer.getCulledCount() << "/" - << renderer.getRenderer().getTextureCount() << "/" - << renderer.getRenderer().getBufferCount() << "\n" - << "Timescale: " << world->state->basic.timeScale; - - TextRenderer::TextInfo ti; - ti.font = FONT_ARIAL; - ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL); - ti.screenPosition = glm::vec2(10.f, 10.f); - ti.size = 15.f; - ti.baseColour = glm::u8vec3(255); - renderer.text.renderText(ti); - - /*while( engine->log.size() > 0 && engine->log.front().time + 10.f < - engine->gameTime ) { - engine->log.pop_front(); - } - - ti.screenPosition = glm::vec2( 10.f, 500.f ); - ti.size = 15.f; - for(auto it = engine->log.begin(); it != engine->log.end(); ++it) { - ti.text = it->message; - switch(it->type) { - case GameWorld::LogEntry::Error: - ti.baseColour = glm::vec3(1.f, 0.f, 0.f); - break; - case GameWorld::LogEntry::Warning: - ti.baseColour = glm::vec3(1.f, 1.f, 0.f); - break; - default: - ti.baseColour = glm::vec3(1.f, 1.f, 1.f); - break; - } - - // Interpolate the color - // c.a = (engine->gameTime - it->time > 5.f) ? 255 - (((engine->gameTime - - it->time) - 5.f)/5.f) * 255 : 255; - // text.setColor(c); - - engine->renderer.text.renderText(ti); - ti.screenPosition.y -= ti.size; - }*/ -} - -void RWGame::renderDebugPaths(float time) { - RW_UNUSED(time); - +void RWGame::renderDebugPaths() { btVector3 roadColour(1.f, 0.f, 0.f); btVector3 pedColour(0.f, 0.f, 1.f); @@ -872,74 +800,6 @@ void RWGame::renderDebugPaths(float time) { debug.flush(renderer); } -void RWGame::renderDebugObjects(float time, ViewCamera& camera) { - RW_UNUSED(time); - - std::stringstream ss; - - ss << "Models: " << data.modelinfo.size() << "\n" - << "Dynamic Objects:\n" - << " Vehicles: " << world->vehiclePool.objects.size() << "\n" - << " Peds: " << world->pedestrianPool.objects.size() << "\n"; - - TextRenderer::TextInfo ti; - ti.font = FONT_ARIAL; - ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL); - ti.screenPosition = glm::vec2(10.f, 10.f); - ti.size = 15.f; - ti.baseColour = glm::u8vec3(255); - renderer.text.renderText(ti); - - // Render worldspace overlay for nearby objects - constexpr float kNearbyDistance = 25.f; - const auto& view = camera.position; - const auto& model = camera.getView(); - const auto& proj = camera.frustum.projection(); - const auto& size = getWindow().getSize(); - glm::vec4 viewport(0.f, 0.f, size.x, size.y); - auto isnearby = [&](GameObject* o) { - return glm::distance2(o->getPosition(), view) < - kNearbyDistance * kNearbyDistance; - }; - auto showdata = [&](GameObject* o, std::stringstream& ss) { - auto screen = glm::project(o->getPosition(), model, proj, viewport); - if (screen.z >= 1.f) { - return; - } - ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL); - screen.y = viewport.w - screen.y; - ti.screenPosition = glm::vec2(screen); - ti.size = 10.f; - renderer.text.renderText(ti); - }; - - for (auto& p : world->vehiclePool.objects) { - if (!isnearby(p.second.get())) continue; - auto v = static_cast(p.second.get()); - - std::stringstream ss; - ss << v->getVehicle()->vehiclename_ << "\n" - << (v->isFlipped() ? "Flipped" : "Upright") << "\n" - << (v->isStopped() ? "Stopped" : "Moving") << "\n" - << v->getVelocity() << "m/s\n"; - - showdata(v, ss); - } - for (auto& p : world->pedestrianPool.objects) { - if (!isnearby(p.second.get())) continue; - auto c = static_cast(p.second.get()); - const auto& state = c->getCurrentState(); - auto act = c->controller->getCurrentActivity(); - - std::stringstream ss; - ss << "Health: " << state.health << " (" << state.armour << ")\n" - << (c->isAlive() ? "Alive" : "Dead") << "\n" - << "Activity: " << (act ? act->name() : "Idle") << "\n"; - - showdata(c, ss); - } -} - void RWGame::globalKeyEvent(const SDL_Event& event) { const auto toggle_debug = [&](DebugViewMode m) { debugview_ = debugview_ == m ? DebugViewMode::Disabled : m; diff --git a/rwgame/RWGame.hpp b/rwgame/RWGame.hpp index d8910f50..ffd11aba 100644 --- a/rwgame/RWGame.hpp +++ b/rwgame/RWGame.hpp @@ -22,6 +22,16 @@ #include class RWGame final : public GameBase { +public: + enum class DebugViewMode { + Disabled, + General, + Physics, + Navigation, + Objects + }; + +private: GameData data; GameRenderer renderer; RWImGui imgui; @@ -40,14 +50,6 @@ class RWGame final : public GameBase { bool inFocus = true; ViewCamera currentCam; - enum class DebugViewMode { - Disabled, - General, - Physics, - Navigation, - Objects - }; - DebugViewMode debugview_ = DebugViewMode::Disabled; int lastDraws{0}; /// Number of draws issued for the last frame. @@ -92,6 +94,10 @@ public: return hudDrawer; } + DebugViewMode getDebugViewMode() const { + return debugview_; + } + bool hitWorldRay(glm::vec3& hit, glm::vec3& normal, GameObject** object = nullptr); @@ -112,9 +118,7 @@ private: void tick(float dt); void render(float alpha, float dt); - void renderDebugStats(float time); - void renderDebugPaths(float time); - void renderDebugObjects(float time, ViewCamera& camera); + void renderDebugPaths(); void handleCheatInput(char symbol); @@ -124,7 +128,7 @@ private: float tickWorld(const float deltaTime, float accumulatedTime); - void renderDebugView(float time, ViewCamera &viewCam); + void renderDebugView(); void tickObjects(float dt) const; }; diff --git a/rwgame/RWImGui.cpp b/rwgame/RWImGui.cpp index d3affa05..d58ab49a 100644 --- a/rwgame/RWImGui.cpp +++ b/rwgame/RWImGui.cpp @@ -1,5 +1,9 @@ #include "RWImGui.hpp" +#include +#include +#include + #ifdef RW_IMGUI #include "RWGame.hpp" @@ -8,7 +12,125 @@ #include #include +#include + #include +#include + +namespace { +void WindowDebugStats(RWGame& game) { + auto& io = ImGui::GetIO(); + + auto time_ms = 1000.0f / io.Framerate; + constexpr size_t average_every_frame = 240; + static float times[average_every_frame]; + static size_t times_index = 0; + static double time_average = 0, time_min = 0, time_max = 0; + times[times_index++] = time_ms; + if (times_index >= average_every_frame) { + times_index = 0; + time_average = 0; + time_min = std::numeric_limits::max(); + time_max = std::numeric_limits::lowest(); + + for (double time : times) { + time_average += time; + time_min = std::min(time, time_min); + time_max = std::max(time, time_max); + } + time_average /= average_every_frame; + } + + const auto& world = game.getWorld(); + auto& renderer = game.getRenderer(); + + ImGui::SetNextWindowPos({20.f, 20.f}); + ImGui::Begin("Engine Information", nullptr, + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs); + ImGui::Text("%.3f ms/frame (%.1f FPS)\n%.3f / %.3f / %.3f ms", + static_cast(1000.0f / io.Framerate), + static_cast(io.Framerate), time_average, time_min, + time_max); + ImGui::Text("Timescale %.2f", + static_cast(world->state->basic.timeScale)); + ImGui::Text("%i Drawn %lu Culled", renderer.getRenderer().getDrawCount(), + renderer.getCulledCount()); + ImGui::Text("%i Textures %i Buffers", + renderer.getRenderer().getTextureCount(), + renderer.getRenderer().getBufferCount()); + ImGui::End(); +} + +void WindowDebugObjects(RWGame& game, const ViewCamera& camera) { + auto& data = game.getGameData(); + auto world = game.getWorld(); + + ImGui::SetNextWindowPos({20.f, 20.f}); + ImGui::Begin("Object Information", nullptr, + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs); + ImGui::Text("%lu Models", data.modelinfo.size()); + ImGui::Text("Dynamic Objects\n %lu Vehicles\n %lu Peds", + world->vehiclePool.objects.size(), + world->pedestrianPool.objects.size()); + ImGui::End(); + + // Render worldspace overlay for nearby objects + constexpr float kNearbyDistance = 25.f; + const auto& view = camera.position; + const auto& model = camera.getView(); + const auto& proj = camera.frustum.projection(); + const auto& size = game.getWindow().getSize(); + glm::vec4 viewport(0.f, 0.f, size.x, size.y); + auto isnearby = [&](GameObject* o) { + return glm::distance2(o->getPosition(), view) < + kNearbyDistance * kNearbyDistance; + }; + auto showdata = [&](GameObject* o, std::stringstream& ss) { + auto screen = glm::project(o->getPosition(), model, proj, viewport); + if (screen.z >= 1.f) { + return; + } + ImGui::SetNextWindowPos({screen.x, viewport.w - screen.y}, 0, + {0.5f, 0.5f}); + ImGui::Begin( + std::to_string(reinterpret_cast(o)).c_str(), nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs); + ImGui::Text("%s", ss.str().c_str()); + ImGui::End(); + }; + + for (auto& p : world->vehiclePool.objects) { + if (!isnearby(p.second.get())) continue; + auto v = static_cast(p.second.get()); + + std::stringstream ss; + ss << v->getVehicle()->vehiclename_ << "\n" + << (v->isFlipped() ? "Flipped" : "Upright") << "\n" + << (v->isStopped() ? "Stopped" : "Moving") << "\n" + << v->getVelocity() << "m/s\n"; + + showdata(v, ss); + } + for (auto& p : world->pedestrianPool.objects) { + if (!isnearby(p.second.get())) continue; + auto c = static_cast(p.second.get()); + const auto& state = c->getCurrentState(); + auto act = c->controller->getCurrentActivity(); + + std::stringstream ss; + ss << "Health: " << state.health << " (" << state.armour << ")\n" + << (c->isAlive() ? "Alive" : "Dead") << "\n" + << "Activity: " << (act ? act->name() : "Idle") << "\n"; + + showdata(c, ss); + } +} +} // namespace RWImGui::RWImGui(RWGame &game) : _game(game) { @@ -39,7 +161,7 @@ void RWImGui::destroy() { _context = nullptr; } -bool RWImGui::process_event(SDL_Event &event) { +bool RWImGui::processEvent(SDL_Event& event) { if (!_context) { return false; } @@ -49,27 +171,32 @@ bool RWImGui::process_event(SDL_Event &event) { return io.WantCaptureMouse || io.WantCaptureKeyboard; } -void RWImGui::tick() { +void RWImGui::startFrame() { if (!_context) { return; } ImGui::SetCurrentContext(_context); - auto& io = ImGui::GetIO(); auto [window, sdl_glcontext] = _game.getWindow().getSDLContext(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(window); ImGui::NewFrame(); +} - static float f = 0.0f; +void RWImGui::endFrame(const ViewCamera& camera) { + switch (_game.getDebugViewMode()) { + case RWGame::DebugViewMode::General: + WindowDebugStats(_game); + break; + case RWGame::DebugViewMode::Objects: + WindowDebugObjects(_game, camera); + break; + default: + break; + } - ImGui::Begin("Hello, world!"); - ImGui::Text("Hello, world!"); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", static_cast(1000.0f / io.Framerate), static_cast(io.Framerate)); ImGui::End(); - - static bool show_demo_window = true; + static bool show_demo_window = false; if (show_demo_window) { ImGui::ShowDemoWindow(&show_demo_window); } diff --git a/rwgame/RWImGui.hpp b/rwgame/RWImGui.hpp index cb87d08b..765d0a3a 100644 --- a/rwgame/RWImGui.hpp +++ b/rwgame/RWImGui.hpp @@ -5,6 +5,7 @@ class RWGame; struct ImGuiContext; +class ViewCamera; class RWImGui { RWGame &_game; @@ -14,8 +15,9 @@ public: ~RWImGui(); void init(); void destroy(); - bool process_event(SDL_Event &event); - void tick(); + bool processEvent(SDL_Event &event); + void startFrame(); + void endFrame(const ViewCamera &); }; #endif // RWGAME_RWIMGUI_HPP From baeffe6c8fd1ea635a744511b64c1038489df090 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 22 May 2019 22:55:03 +0100 Subject: [PATCH 6/8] Use ImGui for debug menu --- rwgame/states/DebugState.cpp | 308 ++++++++++++++++------------------- rwgame/states/DebugState.hpp | 14 +- 2 files changed, 151 insertions(+), 171 deletions(-) diff --git a/rwgame/states/DebugState.cpp b/rwgame/states/DebugState.cpp index f2460d41..fed4b2b3 100644 --- a/rwgame/states/DebugState.cpp +++ b/rwgame/states/DebugState.cpp @@ -17,10 +17,7 @@ #include #include -constexpr float kDebugEntryHeight = 14.f; -constexpr float kDebugEntryHeightMissions = 12.f; -constexpr int kDebugFont = 2; -const glm::vec2 kDebugMenuOffset = glm::vec2(10.f, 50.f); +#include static void jumpCharacter(RWGame* game, CharacterObject* player, const glm::vec3& target, bool ground = true) { @@ -38,126 +35,133 @@ static void jumpCharacter(RWGame* game, CharacterObject* player, } } -Menu DebugState::createDebugMenu() { +void DebugState::drawDebugMenu() { CharacterObject* player = nullptr; if (game->getWorld()->getPlayer()) { player = game->getWorld()->getPlayer()->getCharacter(); } - Menu menu{ - {{"Jump to Debug Camera", - [=] { - jumpCharacter(game, player, - _debugCam.position + - _debugCam.rotation * glm::vec3(3.f, 0.f, 0.f), - false); - }}, - {"-Map", [=] { setNextMenu(createMapMenu()); }}, - {"-Vehicles", [=] { setNextMenu(createVehicleMenu()); }}, - {"-AI", [=] { setNextMenu(createAIMenu()); }}, - {"-Weapons", [=] { setNextMenu(createWeaponMenu()); }}, - {"-Weather", [=] { setNextMenu(createWeatherMenu()); }}, - {"-Missions", [=] { setNextMenu(createMissionsMenu()); }}, - {"Set Super Jump", [=] { player->setJumpSpeed(20.f); }}, - {"Set Normal Jump", - [=] { player->setJumpSpeed(CharacterObject::DefaultJumpSpeed); }}, - {"Full Health", [=] { player->getCurrentState().health = 100.f; }}, - {"Full Armour", [=] { player->getCurrentState().armour = 100.f; }}, - {"Cull Here", - [=] { game->getRenderer().setCullOverride(true, _debugCam); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight}; + ImGui::Begin("Debug Tools"); - // Optional block if the player is in a vehicle - auto cv = player->getCurrentVehicle(); - if (cv) { - menu.lambda("Flip vehicle", [=] { - cv->setRotation(cv->getRotation() * - glm::quat(glm::vec3(0.f, glm::pi(), 0.f))); - }); + if (player && ImGui::BeginMenu("Game")) { + if (ImGui::MenuItem("Set Super Jump")) { + player->setJumpSpeed(20.f); + } + if (ImGui::MenuItem("Set Normal Jump")) { + player->setJumpSpeed(CharacterObject::DefaultJumpSpeed); + } + + if (ImGui::MenuItem("Full Health")) { + player->getCurrentState().health = 100.f; + } + if (ImGui::MenuItem("Full Armour")) { + player->getCurrentState().armour = 100.f; + } + + // Optional block if the player is in a vehicle + if (auto cv = player->getCurrentVehicle(); cv) { + if (ImGui::MenuItem("Flip Vehicle")) { + cv->setRotation( + cv->getRotation() * + glm::quat(glm::vec3(0.f, glm::pi(), 0.f))); + } + } + + if (ImGui::MenuItem("Cull Here")) { + game->getRenderer().setCullOverride(true, _debugCam); + } + + ImGui::EndMenu(); } - return menu; + if (ImGui::BeginMenu("Map")) { + drawMapMenu(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Vehicle")) { + drawVehicleMenu(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("AI")) { + drawAIMenu(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Weapons")) { + drawWeaponMenu(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Weather")) { + drawWeatherMenu(); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Missions")) { + drawMissionsMenu(); + ImGui::EndMenu(); + } + + ImGui::End(); } -Menu DebugState::createMapMenu() { +void DebugState::drawMapMenu() { CharacterObject* player = nullptr; if (game->getWorld()->getPlayer()) { player = game->getWorld()->getPlayer()->getCharacter(); } - Menu menu{ - {{"Back", [=] { setNextMenu(createDebugMenu()); }}, - {"Jump to Docks", - [=] { - jumpCharacter(game, player, glm::vec3(1390.f, -837.f, 100.f)); - }}, - {"Jump to Garage", - [=] { jumpCharacter(game, player, glm::vec3(270.f, -605.f, 40.f)); }}, - {"Jump to Airport", - [=] { - jumpCharacter(game, player, glm::vec3(-950.f, -980.f, 12.f)); - }}, - {"Jump to Hideout", - [=] { - jumpCharacter(game, player, glm::vec3(875.0, -309.0, 100.0)); - }}, - {"Jump to Luigi's", - [=] { - jumpCharacter(game, player, glm::vec3(902.75, -425.56, 100.0)); - }}, - {"Jump to Hospital", - [=] { - jumpCharacter(game, player, glm::vec3(1123.77, -569.15, 100.0)); - }}, - {"Unsolid garage doors", - [=] { - static constexpr std::array garageDoorModels{ - {"8ballsuburbandoor", "amcogaragedoor", - "bankjobdoor", "bombdoor", - "crushercrush", "crushertop", - "door2_garage", "door3_garage", - "door4_garage", "door_bombshop", - "door_col_compnd_01", "door_col_compnd_02", - "door_col_compnd_03", "door_col_compnd_04", - "door_col_compnd_05", "door_jmsgrage", - "door_sfehousegrge", "double_garage_dr", - "impex_door", "impexpsubgrgdoor", - "ind_plyrwoor", "ind_slidedoor", - "jamesgrge_kb", "leveldoor2", - "oddjgaragdoor", "plysve_gragedoor", - "SalvGarage", "shedgaragedoor", - "Sub_sprayshopdoor", "towergaragedoor1", - "towergaragedoor2", "towergaragedoor3", - "vheistlocdoor"}}; + if (ImGui::MenuItem("Jump to Debug Camera")) { + jumpCharacter( + game, player, + _debugCam.position + _debugCam.rotation * glm::vec3(3.f, 0.f, 0.f), + false); + } - auto gw = game->getWorld(); - for (auto& [id, instancePtr] : gw->instancePool.objects) { - auto obj = static_cast(instancePtr.get()); - if (std::find(garageDoorModels.begin(), - garageDoorModels.end(), - obj->getModelInfo()->name) != - garageDoorModels.end()) { - obj->setSolid(false); - } - } - }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight}; - - return menu; -} - -Menu DebugState::createVehicleMenu() { - Menu menu{ - {{"Back", [=] { setNextMenu(createDebugMenu()); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight, + const std::vector> kInterestingPlaces{ + {"Docks", {1390.f, -837.f, 100.f}}, + {"Garage", {270.f, -605.f, 40.f}}, + {"Airport", {-950.f, -980.f, 12.f}}, + {"Hideout", {875.0, -309.0, 100.0}}, + {"Luigi's", {902.75, -425.56, 100.0}}, + {"Hospital", {1123.77, -569.15, 100.0}}, }; + for (const auto& [name, pos] : kInterestingPlaces) { + if (ImGui::MenuItem((std::string("Jump to ") + name).c_str())) { + jumpCharacter(game, player, pos); + } + } + + if (ImGui::MenuItem("Unsolid Garage Doors")) { + static constexpr std::array garageDoorModels{ + {"8ballsuburbandoor", "amcogaragedoor", "bankjobdoor", + "bombdoor", "crushercrush", "crushertop", + "door2_garage", "door3_garage", "door4_garage", + "door_bombshop", "door_col_compnd_01", "door_col_compnd_02", + "door_col_compnd_03", "door_col_compnd_04", "door_col_compnd_05", + "door_jmsgrage", "door_sfehousegrge", "double_garage_dr", + "impex_door", "impexpsubgrgdoor", "ind_plyrwoor", + "ind_slidedoor", "jamesgrge_kb", "leveldoor2", + "oddjgaragdoor", "plysve_gragedoor", "SalvGarage", + "shedgaragedoor", "Sub_sprayshopdoor", "towergaragedoor1", + "towergaragedoor2", "towergaragedoor3", "vheistlocdoor"}}; + + auto gw = game->getWorld(); + for (auto& [id, instancePtr] : gw->instancePool.objects) { + auto obj = static_cast(instancePtr.get()); + if (std::find(garageDoorModels.begin(), garageDoorModels.end(), + obj->getModelInfo()->name) != + garageDoorModels.end()) { + obj->setSolid(false); + } + } + } +} + +void DebugState::drawVehicleMenu() { static constexpr std::array, 19> kVehicleTypes{{{"Landstalker", 90}, {"Taxi", 110}, @@ -180,18 +184,13 @@ Menu DebugState::createVehicleMenu() { {"Infernus", 101}}}; for (const auto& [name, id] : kVehicleTypes) { - menu.lambda(name, [this, id = id] { spawnVehicle(id); }); + if (ImGui::MenuItem(name)) { + spawnVehicle(id); + } } - - return menu; } -Menu DebugState::createAIMenu() { - Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight}; - +void DebugState::drawAIMenu() { static constexpr std::array, 6> kPedTypes{{ {"Triad", 12}, @@ -203,10 +202,12 @@ Menu DebugState::createAIMenu() { }}; for (const auto& [name, id] : kPedTypes) { - menu.lambda(name, [this, id = id] { spawnFollower(id); }); + if (ImGui::MenuItem(name)) { + spawnFollower(id); + } } - menu.lambda("Kill All Peds", [=] { + if (ImGui::MenuItem("Kill All Peds")) { for (auto& [id, pedestrianPtr] : game->getWorld()->pedestrianPool.objects) { if (pedestrianPtr->getLifetime() == GameObject::PlayerLifetime) { @@ -220,47 +221,31 @@ Menu DebugState::createAIMenu() { 0.f }); } - }); - - return menu; + } } -Menu DebugState::createWeaponMenu() { - Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight}; - +void DebugState::drawWeaponMenu() { for (int i = 1; i < kMaxInventorySlots; ++i) { auto& name = getWorld()->data->weaponData[i].name; - menu.lambda(name, [=] { giveItem(i); }); + if (ImGui::MenuItem(name.c_str())) { + giveItem(i); + } } - - return menu; } -Menu DebugState::createWeatherMenu() { - Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeight}; - - static constexpr std::array w{{"Sunny", "Cloudy", "Rainy", "Foggy"}}; +void DebugState::drawWeatherMenu() { + static constexpr std::array w{ + {"Sunny", "Cloudy", "Rainy", "Foggy"}}; for (std::size_t i = 0; i < w.size(); ++i) { - menu.lambda(w[i], - [=] { game->getWorld()->state->basic.nextWeather = static_cast(i); }); + if (ImGui::MenuItem(w[i])) { + game->getWorld()->state->basic.nextWeather = + static_cast(i); + } } - - return menu; } -Menu DebugState::createMissionsMenu() { - Menu menu{{{"Back", [=] { setNextMenu(createDebugMenu()); }}}, - kDebugMenuOffset, - kDebugFont, - kDebugEntryHeightMissions}; - +void DebugState::drawMissionsMenu() { static constexpr std::array w{{ "Intro Movie", "Hospital Info Scene", @@ -345,7 +330,7 @@ Menu DebugState::createMissionsMenu() { }}; for (std::size_t i = 0; i < w.size(); ++i) { - menu.lambda(w[i], [=] { + if (ImGui::MenuItem(w[i])) { ScriptMachine* vm = game->getScriptVM(); if (vm) { @@ -367,16 +352,12 @@ Menu DebugState::createMissionsMenu() { vm->startThread(offsets[i], true); } - }); + } } - - return menu; } DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd) : State(game), _invertedY(game->getConfig().invertY()) { - this->setNextMenu(createDebugMenu()); - _debugCam.position = vp; _debugCam.rotation = vd; } @@ -400,19 +381,18 @@ void DebugState::tick(float dt) { } void DebugState::draw(GameRenderer& r) { - // Draw useful information like camera position. - std::stringstream ss; - ss << "Camera Position: " << glm::to_string(_debugCam.position) << "\n"; - auto zone = getWorld()->data->findZoneAt(_debugCam.position); - ss << (zone ? zone->name : "No Zone") << "\n"; + ImGui::SetNextWindowPos({20.f, 20.f}); + ImGui::Begin("Debug Info", nullptr, + ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs); - TextRenderer::TextInfo ti; - ti.font = FONT_ARIAL; - ti.text = GameStringUtil::fromString(ss.str(), ti.font); - ti.screenPosition = glm::vec2(10.f, 10.f); - ti.size = 15.f; - ti.baseColour = glm::u8vec3(255); - r.text.renderText(ti); + ImGui::Text("Camera: %s", glm::to_string(_debugCam.position).c_str()); + auto zone = getWorld()->data->findZoneAt(_debugCam.position); + ImGui::Text("Zone: %s", zone ? zone->name.c_str() : "No Zone"); + ImGui::End(); + + drawDebugMenu(); State::draw(r); } diff --git a/rwgame/states/DebugState.hpp b/rwgame/states/DebugState.hpp index 7b0839f1..8355def5 100644 --- a/rwgame/states/DebugState.hpp +++ b/rwgame/states/DebugState.hpp @@ -18,13 +18,13 @@ class DebugState final : public State { bool _sonicMode = false; bool _invertedY; - Menu createDebugMenu(); - Menu createMapMenu(); - Menu createVehicleMenu(); - Menu createAIMenu(); - Menu createWeaponMenu(); - Menu createWeatherMenu(); - Menu createMissionsMenu(); + void drawDebugMenu(); + void drawMapMenu(); + void drawVehicleMenu(); + void drawAIMenu(); + void drawWeaponMenu(); + void drawWeatherMenu(); + void drawMissionsMenu(); public: DebugState(RWGame* game, const glm::vec3& vp = {}, From 35c90d1ebc5be02f7c206a9714cab824a93cdd2d Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 22 May 2019 23:10:01 +0100 Subject: [PATCH 7/8] Remove ImGui configuration option --- cmake_options.cmake | 1 - external/CMakeLists.txt | 4 +--- rwgame/CMakeLists.txt | 18 ++++++++---------- rwgame/RWImGui.cpp | 23 ----------------------- 4 files changed, 9 insertions(+), 37 deletions(-) diff --git a/cmake_options.cmake b/cmake_options.cmake index b6362cf1..d0d10cb0 100644 --- a/cmake_options.cmake +++ b/cmake_options.cmake @@ -6,7 +6,6 @@ option(BUILD_VIEWER "Build GUI data viewer") option(ENABLE_SCRIPT_DEBUG "Enable verbose script execution") option(ENABLE_PROFILING "Enable detailed profiling metrics") -option(ENABLE_IMGUI "Enable imgui plugin") option(TEST_DATA "Enable tests that require game data") diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 9c4fa96e..8b03d62e 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -2,6 +2,4 @@ if(ENABLE_PROFILING) add_subdirectory(microprofile) endif() -if(ENABLE_IMGUI) - add_subdirectory(imgui) -endif() +add_subdirectory(imgui) diff --git a/rwgame/CMakeLists.txt b/rwgame/CMakeLists.txt index 3996ef0a..86e30200 100644 --- a/rwgame/CMakeLists.txt +++ b/rwgame/CMakeLists.txt @@ -71,17 +71,15 @@ target_link_libraries(librwgame SDL2::SDL2 ) -if(ENABLE_IMGUI) - target_compile_definitions(librwgame - PUBLIC - RW_IMGUI - ) +target_compile_definitions(librwgame + PUBLIC + RW_IMGUI + ) - target_link_libraries(librwgame - PUBLIC - imgui::sdl_gl3 - ) -endif() +target_link_libraries(librwgame + PUBLIC + imgui::sdl_gl3 + ) add_executable(rwgame main.cpp diff --git a/rwgame/RWImGui.cpp b/rwgame/RWImGui.cpp index d58ab49a..6ee496a5 100644 --- a/rwgame/RWImGui.cpp +++ b/rwgame/RWImGui.cpp @@ -4,8 +4,6 @@ #include #include -#ifdef RW_IMGUI - #include "RWGame.hpp" #include @@ -204,24 +202,3 @@ void RWImGui::endFrame(const ViewCamera& camera) { ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } - -#else - -RWImGui::RWImGui(RWGame &game) - : _game(game) { -} - -RWImGui::~RWImGui() { - destroy(); -} - -RWImGui::init(SDL_Window *window, SDL_GLContext context) { -} - -RWImGui::destroy() { -} - -RWImGui::process_event(SDL_Event &event) { -} - -#endif From e759101a47365319886986ff97f6cb5cd17fda2d Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Thu, 23 May 2019 23:38:35 +0100 Subject: [PATCH 8/8] Provide tests for ViewCamera --- tests/CMakeLists.txt | 1 + tests/main.cpp | 2 +- tests/test_Globals.hpp | 6 ++++++ tests/test_ViewCamera.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/test_ViewCamera.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 23438431..b2aae0a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,6 +34,7 @@ set(TESTS Text TrafficDirector Vehicle + ViewCamera VisualFX Weapon World diff --git a/tests/main.cpp b/tests/main.cpp index 07607815..a11ed160 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -3,6 +3,6 @@ #include "test_Globals.hpp" std::ostream& operator<<(std::ostream& stream, const glm::vec3& v) { - stream << v.x << " " << v.y << " " << v.z; + stream << glm::to_string(v); return stream; } diff --git a/tests/test_Globals.hpp b/tests/test_Globals.hpp index 760e0680..bba2f939 100644 --- a/tests/test_Globals.hpp +++ b/tests/test_Globals.hpp @@ -45,6 +45,12 @@ struct print_log_value { s << glm::to_string(v); } }; +template <> +struct print_log_value { + void operator()(std::ostream& s, glm::vec4 const& v) { + s << glm::to_string(v); + } +}; BOOST_NS_MAGIC_CLOSING } } diff --git a/tests/test_ViewCamera.cpp b/tests/test_ViewCamera.cpp new file mode 100644 index 00000000..056f411b --- /dev/null +++ b/tests/test_ViewCamera.cpp @@ -0,0 +1,26 @@ +#include +#include "test_Globals.hpp" +#include + +namespace { + +struct CameraFixture { + ViewCamera camera_ { + {1.f, 2.f, 3.f} + }; +}; +} + +BOOST_AUTO_TEST_SUITE(ViewCameraTests) + +BOOST_FIXTURE_TEST_CASE(test_creation, CameraFixture) { + BOOST_CHECK_EQUAL(camera_.position, glm::vec3(1.f, 2.f, 3.f)); +} + +BOOST_FIXTURE_TEST_CASE(test_view_matrix, CameraFixture) { + const auto& view = camera_.getView(); + BOOST_CHECK_EQUAL(view[3], glm::vec4(2.f, -3.f, 1.f, 1.f)); +} + + +BOOST_AUTO_TEST_SUITE_END()