diff --git a/Runtime/CMain.cpp b/Runtime/CMain.cpp index b80c866cd..0b9df20c0 100644 --- a/Runtime/CMain.cpp +++ b/Runtime/CMain.cpp @@ -417,7 +417,7 @@ public: } void onAppWindowResized(const aurora::WindowSize& size) noexcept override { - CGraphics::SetViewportResolution({static_cast(size.width), static_cast(size.height)}); + CGraphics::SetViewportResolution({static_cast(size.fb_width), static_cast(size.fb_height)}); } void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept override { diff --git a/aurora/CMakeLists.txt b/aurora/CMakeLists.txt index 3315f623a..c4243dcfc 100644 --- a/aurora/CMakeLists.txt +++ b/aurora/CMakeLists.txt @@ -27,9 +27,6 @@ add_library(aurora STATIC lib/gfx/movie_player/shader.cpp lib/gfx/textured_quad/shader.cpp lib/gfx/colored_quad/shader.cpp - # TODO move to imgui? or move imgui impl to here? - ../extern/imgui/backends/imgui_impl_sdl.cpp - ../extern/imgui/backends/imgui_impl_wgpu.cpp ) target_compile_definitions(aurora PRIVATE IMGUI_USER_CONFIG="imconfig_user.h") # IMGUI_USE_WCHAR32 target_include_directories(aurora PUBLIC include ../Runtime) diff --git a/aurora/include/aurora/aurora.hpp b/aurora/include/aurora/aurora.hpp index b41970b68..5351c5bef 100644 --- a/aurora/include/aurora/aurora.hpp +++ b/aurora/include/aurora/aurora.hpp @@ -174,6 +174,11 @@ struct Icon { struct WindowSize { uint32_t width; uint32_t height; + uint32_t fb_width; + uint32_t fb_height; + float scale; + + bool operator<=>(const WindowSize& rhs) const = default; }; enum class MouseButton { None = 0, diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index b54f60c6f..fd3b07877 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -15,10 +15,10 @@ static logvisor::Module Log("aurora"); // TODO: Move global state to a class/struct? static std::unique_ptr g_AppDelegate; static std::vector g_Args; -static float g_AppDpi = 1.f; // SDL -static SDL_Window* g_Window; +static SDL_Window* g_window; +static WindowSize g_windowSize; // GPU using gpu::g_depthBuffer; @@ -40,7 +40,7 @@ static void set_window_icon(Icon icon) noexcept { Log.report(logvisor::Fatal, FMT_STRING("Failed to create icon surface: {}"), SDL_GetError()); unreachable(); } - SDL_SetWindowIcon(g_Window, iconSurface); + SDL_SetWindowIcon(g_window, iconSurface); SDL_FreeSurface(iconSurface); } @@ -58,26 +58,26 @@ static bool poll_events() noexcept { case SDL_WINDOWEVENT_HIDDEN: { break; } - case SDL_WINDOWEVENT_EXPOSED: { - break; - } case SDL_WINDOWEVENT_MOVED: { g_AppDelegate->onAppWindowMoved(event.window.data1, event.window.data2); break; } + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_DISPLAY_CHANGED: + case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED: - case SDL_WINDOWEVENT_RESIZED: { - gpu::resize_swapchain(event.window.data1, event.window.data2); - g_AppDelegate->onAppWindowResized( - {static_cast(event.window.data1), static_cast(event.window.data2)}); - break; - } - case SDL_WINDOWEVENT_MINIMIZED: { - // TODO: handle minimized event - break; - } + case SDL_WINDOWEVENT_MINIMIZED: case SDL_WINDOWEVENT_MAXIMIZED: { - // TODO: handle maximized event + const auto size = get_window_size(); + if (size == g_windowSize) { + break; + } + if (size.scale != g_windowSize.scale) { + g_AppDelegate->onAppDisplayScaleChanged(size.scale); + } + g_windowSize = size; + gpu::resize_swapchain(size.fb_width, size.fb_height); + g_AppDelegate->onAppWindowResized(size); break; } case SDL_WINDOWEVENT_RESTORED: { @@ -112,17 +112,6 @@ static bool poll_events() noexcept { // TODO: handle hit test? break; } - case SDL_WINDOWEVENT_DISPLAY_CHANGED: { - printf("DISPLAY_CHANGED!\n"); - float scale = 1.0f; - if (SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(g_Window), nullptr, &scale, nullptr) == 0) { - scale /= 96.0f; - if (g_AppDpi != scale) { - g_AppDelegate->onAppDisplayScaleChanged(scale); - } - } - break; - } } break; } @@ -259,30 +248,29 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) default: break; } - g_Window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, flags); - if (g_Window == nullptr) { + g_window = SDL_CreateWindow("Metaforce", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, flags); + if (g_window == nullptr) { Log.report(logvisor::Fatal, FMT_STRING("Error creating window: {}"), SDL_GetError()); unreachable(); } set_window_icon(std::move(icon)); - gpu::initialize(g_Window); + gpu::initialize(g_window); gfx::initialize(); - g_AppDpi = 1.0f; - if (SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(g_Window), nullptr, &g_AppDpi, nullptr) == 0) { - g_AppDpi /= 96.0f; - } imgui::create_context(); - g_AppDelegate->onImGuiInit(g_AppDpi); - imgui::initialize(g_Window); + const auto size = get_window_size(); + Log.report(logvisor::Info, FMT_STRING("Using framebuffer size {}x{} scale {}"), size.fb_width, size.fb_height, + size.scale); + g_AppDelegate->onImGuiInit(size.scale); + imgui::initialize(g_window); g_AppDelegate->onImGuiAddTextures(); g_AppDelegate->onAppLaunched(); - g_AppDelegate->onAppWindowResized(get_window_size()); + g_AppDelegate->onAppWindowResized(size); while (poll_events()) { - imgui::new_frame(); + imgui::new_frame(g_windowSize); if (!g_AppDelegate->onAppIdle(ImGui::GetIO().DeltaTime)) { break; } @@ -354,19 +342,26 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) imgui::shutdown(); gfx::shutdown(); gpu::shutdown(); - SDL_DestroyWindow(g_Window); + SDL_DestroyWindow(g_window); SDL_Quit(); } std::vector get_args() noexcept { return g_Args; } WindowSize get_window_size() noexcept { - int width, height; - SDL_GetWindowSize(g_Window, &width, &height); - return {static_cast(width), static_cast(height)}; + int width, height, fb_w, fb_h; + SDL_GetWindowSize(g_window, &width, &height); + SDL_GL_GetDrawableSize(g_window, &fb_w, &fb_h); + return { + .width = static_cast(width), + .height = static_cast(height), + .fb_width = static_cast(fb_w), + .fb_height = static_cast(fb_h), + .scale = static_cast(fb_w) / static_cast(width), + }; } -void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_Window, title.c_str()); } +void set_window_title(zstring_view title) noexcept { SDL_SetWindowTitle(g_window, title.c_str()); } Backend get_backend() noexcept { switch (gpu::g_backendType) { @@ -392,7 +387,7 @@ Backend get_backend() noexcept { std::string_view get_backend_string() noexcept { return magic_enum::enum_name(gpu::g_backendType); } void set_fullscreen(bool fullscreen) noexcept { - SDL_SetWindowFullscreen(g_Window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); + SDL_SetWindowFullscreen(g_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); } int32_t get_controller_player_index(uint32_t instance) noexcept { return input::player_index(instance); } @@ -409,5 +404,6 @@ void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t uint32_t duration_ms) noexcept { input::controller_rumble(instance, low_freq_intensity, high_freq_intensity, duration_ms); } + std::string get_controller_name(uint32_t instance) noexcept { return input::controller_name(instance); } } // namespace aurora diff --git a/aurora/lib/gpu.cpp b/aurora/lib/gpu.cpp index 84141587b..7fdf63a31 100644 --- a/aurora/lib/gpu.cpp +++ b/aurora/lib/gpu.cpp @@ -1,10 +1,10 @@ #include "gpu.hpp" +#include #include #include #include #include -#include #include #include "dawn/BackendBinding.hpp" @@ -168,7 +168,7 @@ void initialize(SDL_Window* window) { { int width = 0; int height = 0; - SDL_GetWindowSize(window, &width, &height); + SDL_GL_GetDrawableSize(window, &width, &height); g_graphicsConfig = GraphicsConfig{ .width = static_cast(width), .height = static_cast(height), diff --git a/aurora/lib/imgui.cpp b/aurora/lib/imgui.cpp index 1711028a5..940f646f8 100644 --- a/aurora/lib/imgui.cpp +++ b/aurora/lib/imgui.cpp @@ -2,15 +2,20 @@ #include "gpu.hpp" +#include +#include #include -#include -#include #include +#include "../extern/imgui/backends/imgui_impl_sdl.cpp" +#include "../extern/imgui/backends/imgui_impl_wgpu.cpp" + namespace aurora::imgui { using gpu::g_device; using gpu::g_queue; +static float g_scale; + void create_context() noexcept { IMGUI_CHECKVERSION(); ImGui::CreateContext(); @@ -19,9 +24,9 @@ void create_context() noexcept { } void initialize(SDL_Window* window) noexcept { - // this just passes through to ImGui_ImplSDL2_Init (private) - // may need to change in the future - ImGui_ImplSDL2_InitForMetal(window); + ImGui_ImplSDL2_Init(window, nullptr); + // Disable MouseCanUseGlobalState for scaling purposes + ImGui_ImplSDL2_GetBackendData()->MouseCanUseGlobalState = false; ImGui_ImplWGPU_Init(g_device.Get(), 1, static_cast(gpu::g_graphicsConfig.colorFormat)); } @@ -31,17 +36,35 @@ void shutdown() noexcept { ImGui::DestroyContext(); } -void process_event(const SDL_Event& event) noexcept { ImGui_ImplSDL2_ProcessEvent(&event); } +void process_event(const SDL_Event& event) noexcept { + auto newEvent = event; + if (newEvent.type == SDL_MOUSEMOTION) { + auto& io = ImGui::GetIO(); + // Scale up mouse coordinates + io.AddMousePosEvent(static_cast(newEvent.motion.x) * g_scale, + static_cast(newEvent.motion.y) * g_scale); + return; + } + ImGui_ImplSDL2_ProcessEvent(&newEvent); +} -void new_frame() noexcept { +void new_frame(const WindowSize& size) noexcept { ImGui_ImplWGPU_NewFrame(); ImGui_ImplSDL2_NewFrame(); + + // Render at full DPI + g_scale = size.scale; + ImGui::GetIO().DisplaySize = ImVec2{static_cast(size.fb_width), static_cast(size.fb_height)}; ImGui::NewFrame(); } void render(const wgpu::RenderPassEncoder& pass) noexcept { ImGui::Render(); - ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass.Get()); + + auto* data = ImGui::GetDrawData(); + // io.DisplayFramebufferScale is informational; we're rendering at full DPI + data->FramebufferScale = {1.f, 1.f}; + ImGui_ImplWGPU_RenderDrawData(data, pass.Get()); } ImTextureID add_texture(uint32_t width, uint32_t height, ArrayRef data) noexcept { diff --git a/aurora/lib/imgui.hpp b/aurora/lib/imgui.hpp index d516f408c..febbfb800 100644 --- a/aurora/lib/imgui.hpp +++ b/aurora/lib/imgui.hpp @@ -7,12 +7,16 @@ namespace wgpu { class RenderPassEncoder; } // namespace wgpu +namespace aurora { +struct WindowSize; +} // namespace aurora + namespace aurora::imgui { void create_context() noexcept; void initialize(SDL_Window* window) noexcept; void shutdown() noexcept; void process_event(const SDL_Event& event) noexcept; -void new_frame() noexcept; +void new_frame(const WindowSize& size) noexcept; void render(const wgpu::RenderPassEncoder& pass) noexcept; } // namespace aurora::imgui diff --git a/imgui/ImGuiEngine.cpp b/imgui/ImGuiEngine.cpp index 8224a73bf..b80b9542d 100644 --- a/imgui/ImGuiEngine.cpp +++ b/imgui/ImGuiEngine.cpp @@ -59,6 +59,7 @@ void ImGuiEngine_Initialize(float scale) { ImGuiEngine::fontLarge = io.Fonts->AddFont(&fontConfig); auto& style = ImGui::GetStyle(); + style = {}; // Reset sizes style.WindowPadding = ImVec2(15, 15); style.WindowRounding = 5.0f; style.FrameBorderSize = 1.f; diff --git a/imgui/ImGuiEngine.hpp b/imgui/ImGuiEngine.hpp index c1f714480..f5710d8a9 100644 --- a/imgui/ImGuiEngine.hpp +++ b/imgui/ImGuiEngine.hpp @@ -12,7 +12,6 @@ public: static ImTextureID metaforceIcon; }; -// Called from Rust void ImGuiEngine_Initialize(float scale); void ImGuiEngine_AddTextures();