From 117e14d5a5fc75c4dd63d6000535458d966f0ece Mon Sep 17 00:00:00 2001 From: SlowRiot Date: Tue, 31 Mar 2026 22:46:35 +0100 Subject: [PATCH] user-adjustable target device pixel ratio --- backends/imgui_impl_emscripten.cpp | 60 +++++++++++++++++------------- backends/imgui_impl_emscripten.h | 4 ++ 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/backends/imgui_impl_emscripten.cpp b/backends/imgui_impl_emscripten.cpp index 659b99cdf..e813a755d 100644 --- a/backends/imgui_impl_emscripten.cpp +++ b/backends/imgui_impl_emscripten.cpp @@ -4,6 +4,7 @@ // // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-03-31: Emscripten: Added configurable TargetDevicePixelRatio to control how browser device pixels map to Dear ImGui pixels. // 2026-03-31: Emscripten: Reworked KeyboardEvent.code translation to avoid std::unordered_map and added BrowserBack/Forward and F13-F24 mappings. // 2026-03-31: Emscripten: Moved cursor state into backend userdata and replaced cursor restore storage with owned C strings. // 2024-12-09: Inputs: Added special handling for modifier keys to also generate modifier key events. @@ -21,6 +22,8 @@ #include #include +float ImGui_ImplEmscripten_TargetDevicePixelRatio{1.0f}; + namespace { // W3C UI Events KeyboardEvent.code translation helpers @@ -100,18 +103,27 @@ namespace { struct ImGui_ImplEmscripten_Data { - float DevicePixelRatio; - emscripten_browser_cursor_internal::cursor CurrentCursor; - char* CursorToRestore; - - ImGui_ImplEmscripten_Data() - : DevicePixelRatio{1.0f} - , CurrentCursor{emscripten_browser_cursor_internal::cursor::invalid} - , CursorToRestore{nullptr} - { - } + float CssToImGuiScale{1.0f}; + emscripten_browser_cursor_internal::cursor CurrentCursor{emscripten_browser_cursor_internal::cursor::invalid}; + char* CursorToRestore{nullptr}; }; +float get_target_device_pixel_ratio() +{ + IM_ASSERT(ImGui_ImplEmscripten_TargetDevicePixelRatio > 0.0f && "ImGui_ImplEmscripten_TargetDevicePixelRatio must be positive."); + return ImGui_ImplEmscripten_TargetDevicePixelRatio > 0.0f ? ImGui_ImplEmscripten_TargetDevicePixelRatio : 1.0f; +} + +void update_display_properties(ImGuiIO& io, ImGui_ImplEmscripten_Data* bd, float css_width, float css_height) +{ + float const target_device_pixel_ratio{get_target_device_pixel_ratio()}; + float const css_to_imgui_scale{static_cast(emscripten_get_device_pixel_ratio()) / target_device_pixel_ratio}; + bd->CssToImGuiScale = css_to_imgui_scale; + io.DisplaySize.x = css_width * css_to_imgui_scale; + io.DisplaySize.y = css_height * css_to_imgui_scale; + io.DisplayFramebufferScale = ImVec2(target_device_pixel_ratio, target_device_pixel_ratio); +} + // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts ImGui_ImplEmscripten_Data* ImGui_ImplEmscripten_GetBackendData() { @@ -132,10 +144,12 @@ void ImGui_ImplEmscripten_Init() io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // set up initial display size values - bd->DevicePixelRatio = static_cast(emscripten_get_device_pixel_ratio()); - io.DisplaySize.x = static_cast(EM_ASM_INT(return window.innerWidth;)) * bd->DevicePixelRatio; - io.DisplaySize.y = static_cast(EM_ASM_INT(return window.innerHeight;)) * bd->DevicePixelRatio; - io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + update_display_properties( + io, + bd, + static_cast(EM_ASM_INT(return window.innerWidth;)), + static_cast(EM_ASM_INT(return window.innerHeight;)) + ); emscripten_set_mousemove_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, // target @@ -143,10 +157,10 @@ void ImGui_ImplEmscripten_Init() false, // useCapture [](int /*event_type*/, EmscriptenMouseEvent const* mouse_event, void* /*data*/) { // callback, event_type == EMSCRIPTEN_EVENT_MOUSEMOVE ImGui_ImplEmscripten_Data* bd{ImGui_ImplEmscripten_GetBackendData()}; - float const device_pixel_ratio{bd ? bd->DevicePixelRatio : 1.0f}; + float const css_to_imgui_scale{bd ? bd->CssToImGuiScale : 1.0f}; ImGui::GetIO().AddMousePosEvent( - static_cast(mouse_event->clientX) * device_pixel_ratio, - static_cast(mouse_event->clientY) * device_pixel_ratio + static_cast(mouse_event->clientX) * css_to_imgui_scale, + static_cast(mouse_event->clientY) * css_to_imgui_scale ); return true; // the event was consumed } @@ -175,10 +189,10 @@ void ImGui_ImplEmscripten_Init() false, // useCapture [](int /*event_type*/, EmscriptenMouseEvent const* mouse_event, void* /*data*/) { // callback, event_type == EMSCRIPTEN_EVENT_MOUSEENTER ImGui_ImplEmscripten_Data* bd{ImGui_ImplEmscripten_GetBackendData()}; - float const device_pixel_ratio{bd ? bd->DevicePixelRatio : 1.0f}; + float const css_to_imgui_scale{bd ? bd->CssToImGuiScale : 1.0f}; ImGui::GetIO().AddMousePosEvent( - static_cast(mouse_event->clientX) * device_pixel_ratio, - static_cast(mouse_event->clientY) * device_pixel_ratio + static_cast(mouse_event->clientX) * css_to_imgui_scale, + static_cast(mouse_event->clientY) * css_to_imgui_scale ); return true; // the event was consumed } @@ -307,11 +321,7 @@ void ImGui_ImplEmscripten_Init() [](int /*event_type*/, EmscriptenUiEvent const* event, void* /*data*/) { // event_type == EMSCRIPTEN_EVENT_RESIZE ImGuiIO& io{ImGui::GetIO()}; ImGui_ImplEmscripten_Data* bd{ImGui_ImplEmscripten_GetBackendData()}; - float const device_pixel_ratio{static_cast(emscripten_get_device_pixel_ratio())}; - if (bd != nullptr) bd->DevicePixelRatio = device_pixel_ratio; - io.DisplaySize.x = static_cast(event->windowInnerWidth) * device_pixel_ratio; - io.DisplaySize.y = static_cast(event->windowInnerHeight) * device_pixel_ratio; - io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + if (bd != nullptr) update_display_properties(io, bd, static_cast(event->windowInnerWidth), static_cast(event->windowInnerHeight)); return true; // the event was consumed } ); diff --git a/backends/imgui_impl_emscripten.h b/backends/imgui_impl_emscripten.h index a0c1a7d7d..5b23023d5 100644 --- a/backends/imgui_impl_emscripten.h +++ b/backends/imgui_impl_emscripten.h @@ -40,6 +40,10 @@ #error The imgui_impl_emscripten backend requires Emscripten. #endif +// Controls how many device pixels Dear ImGui should target per Dear ImGui pixel. +// Default 1.0f gives 1:1 device-pixel rendering. Set before Init() if you want a different scaling policy. +extern IMGUI_IMPL_API float ImGui_ImplEmscripten_TargetDevicePixelRatio; + // Initialise the Emscripten backend, setting input callbacks. This should be called after ImGui::CreateContext(); IMGUI_IMPL_API void ImGui_ImplEmscripten_Init();