From 9817a937beb8b00ffcfe9a88f539408e2435b241 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Thu, 11 Apr 2024 12:08:11 +0200 Subject: [PATCH] Improve doc / Dpi Params --- src/hello_imgui/doc_api.md | 105 +++++++++++++++++++++++++------- src/hello_imgui/doc_api.src.md | 40 +----------- src/hello_imgui/doc_params.md | 41 ++++++++++--- src/hello_imgui/dpi_aware.h | 108 +++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 69 deletions(-) diff --git a/src/hello_imgui/doc_api.md b/src/hello_imgui/doc_api.md index da526d15..c48080e6 100644 --- a/src/hello_imgui/doc_api.md +++ b/src/hello_imgui/doc_api.md @@ -408,42 +408,101 @@ void ShowAppMenu(RunnerParams & runnerParams); # Handling screens with high DPI -_Note: This part is relevant only for more advanced usages. If you use `HelloImGui::LoadFont()`, and always use `HelloImGui::EmToVec2()` to place widgets, you do not need to worry about DPI handling_ -## Details on DPI handling on different OS +_Note: This part is relevant only for more advanced usages. If you use `HelloImGui::LoadFont()`, + and always use `HelloImGui::EmToVec2()` to place widgets, you do not need to worry about DPI handling_ -Let's consider screen whose physical pixel resolution is 3600x2000, but which will displayed with a scaling factor of 200%, so that widgets do not look too small on it. +## OS specificities -The way it is handled depends on the OS: -- On MacOS, the screen will be seen as having a resolution of 1800x1000, and the OS handles the resizing by itself. -- On Linux, and on Windows if the application is DPI aware, the screen will be seen as having a resolution of 3600x2000. -- On Windows if the application is not DPI aware, the screen will be seen as having a resolution of 1800x1000 +There are several important things to know about high-DPI handling within Hello ImGui and Dear ImGui: -By default, if using the glfw backend, applications will be Dpi aware under windows. -Sdl applications are normally not Dpi aware. However HelloImGui makes them Dpi aware when using the sdl backend. +1. (virtual) screen coordinates vs (physical) pixels +2. DisplayFramebufferScale: Frame buffer size vs window size +3. FontGlobalScale: display-time font scaling factor +4. How to load fonts with the correct size +5. How to get similar window sizes on different OSes/DPI -## Dpi aware Font scaling +## Screen coordinates -`HelloImGui::LoadFont()` will load fonts with the correct size, taking into account the DPI scaling. +Screen coordinates are the coordinates you use to place and size windows on the screen. -If you prefer to use `ImGui::GetIO().Fonts->AddFontFromFileTTF()`, there are two things to know: +**Screen coordinates do not always correspond to physical pixels** -1. You should adjust `ImGui::GetIO().FontGlobalScale`: +- On macOS/iOS retina screens, a screen coordinate corresponds typically + to 2x2 physical pixels (but this may vary if you change the display scaling) +- On most Linux distributions, whenever there is a high DPI screen + you can set the display scale. For example if you set the scale to 300%, + then a screen coordinate will correspond to 3x3 physical pixels +- On Windows, there are two possible situations: + - If the application is DPI aware, a screen coordinate corresponds to 1x1 physical pixel, + and you can use the full extent of your screen resolution. + - If the application is not DPI aware, a screen coordinate may correspond to 2x2 physical pixels + (if the display scaling is set to 200% for example). However, the rendering of your application + will be blurry and will not use the full extent of your screen resolution. + - Notes: + - Applications created with HelloImGui are DPI aware by default (when using glfw and sdl backends). + - SDL applications are normally not DPI aware. However, HelloImGui makes them DPI aware. -Under windows and linux, it should be is 1: no rescaling should be done by ImGui. -Under macOS and emscripten, it may need to bet set to 0.5 (for example it will be 0.5 if the dpi scaling is 200% -on a macOS retina screen) -`HelloImGui::ImGuiDefaultFontGlobalScale()` returns the default value that should be stored inside `ImGui::GetIO().FontGlobalScale`. +## DisplayFramebufferScale +`DisplayFramebufferScale` is the ratio between the frame buffer size and the window size. +The frame buffer size is the size of the internal buffer used by the rendering backend. +It might be bigger than the actual window size. +`ImVec2 ImGui::GetIO().DisplayFramebufferScale` is a factor by which the frame buffer size is bigger than the window size. +It is set by the platform backend after it was initialized, and typically reflects the scaling ratio between +physical pixels and screen coordinates. -2. You should adjust the font size when loading a font: +Under windows, it will always be (1,1). Under macOS / linux, it will reflect the current display scaling. +It will typically be (2,2) on a macOS retina screen. -`HelloImGui::DpiFontLoadingFactor()` returns a factor by which you shall multiply your font sizes when loading them. +Notes: +- As a convenience, `ImGui::GetIO().DisplayFramebufferScale` is mirrored in `HelloImGui::DpiAwareParams::roDisplayFramebufferScale`. +- You cannot change DisplayFramebufferScale manually, it will be reset at each new frame, by asking the platform backend. -`HelloImGui::DpiFontLoadingFactor()` corresponds to: -`DpiWindowSizeFactor() * 1.f / ImGui::GetIO().FontGlobalScale` -where DpiWindowSizeFactor() is equal to `CurrentScreenPixelPerInch / 96` -under windows and linux, 1 under macOS +## FontGlobalScale + +`ImGui::GetIO().FontGlobalScale` is a factor by which fonts glyphs should be scaled at rendering time. +It is typically 1 on windows, and 0.5 on macOS retina screens. + + +## How to load fonts with the correct size + +### Using HelloImGui::LoadFont + +[`HelloImGui::LoadFont()`](https://pthom.github.io/hello_imgui/book/doc_api.html#load-fonts) will load fonts + with the correct size, taking into account the DPI scaling. + +### Using Dear ImGui's AddFontFromFileTTF(): +`ImGui::GetIO().Fonts->AddFontFromFileTTF()` loads a font with a given size, in *physical pixels*. + +If for example, DisplayFramebufferScale is (2,2), and you load a font with a size of 16, it will by default be rendered + with size of 16 *virtual screen coordinate pixels* (i.e. 32 physical pixels). This will lead to blurry text. +To solve this, you should load your font with a size of 16 *virtual screen coordinate pixels* (i.e. 32 physical pixels), +and set `ImGui::GetIO().FontGlobalScale` to 0.5. + +Helpers if using `ImGui::GetIO().Fonts->AddFontFromFileTTF()`: +- `HelloImGui::ImGuiDefaultFontGlobalScale()` returns the default value that should be stored inside `ImGui::GetIO().FontGlobalScale`. +- `HelloImGui::DpiFontLoadingFactor()` returns a factor by which you shall multiply your font sizes when loading them. + + +## Reproducible physical window sizes (in mm or inches) + +### Using HelloImGui +Simply specify a window size that corresponds to theoretical 96 PPI screen (inside `RunnerParams.appWindowParams.windowGeometry.size`) + +### Using your own code to create the backend window +If you prefer to create the window by yourself, its physical size in millimeters may vary widely, +depending on the OS and the current screen DPI setting. +Typically under Windows, your window may appear to be very small if your screen is high DPI. + +To get a similar window size on different OSes/DPI, you should multiply the window size by `HelloImGui::DpiWindowSizeFactor()`. + +Note: DpiWindowSizeFactor() is equal to `CurrentScreenPixelPerInch / 96` under windows and linux, and always 1 under macOS. + +## Fine tune DPI Handling + +See [`HelloImGui::DpiAwareParams`](https://pthom.github.io/hello_imgui/book/doc_params.html#dpi-aware-params) +for more information on how to fine tune DPI handling when using Hello ImGui. diff --git a/src/hello_imgui/doc_api.src.md b/src/hello_imgui/doc_api.src.md index 15db606d..df8fd9ba 100644 --- a/src/hello_imgui/doc_api.src.md +++ b/src/hello_imgui/doc_api.src.md @@ -100,42 +100,4 @@ See [hello_imgui.h](https://github.com/pthom/hello_imgui/blob/master/src/hello_i # Handling screens with high DPI -_Note: This part is relevant only for more advanced usages. If you use `HelloImGui::LoadFont()`, and always use `HelloImGui::EmToVec2()` to place widgets, you do not need to worry about DPI handling_ - -## Details on DPI handling on different OS - -Let's consider screen whose physical pixel resolution is 3600x2000, but which will displayed with a scaling factor of 200%, so that widgets do not look too small on it. - -The way it is handled depends on the OS: -- On MacOS, the screen will be seen as having a resolution of 1800x1000, and the OS handles the resizing by itself. -- On Linux, and on Windows if the application is DPI aware, the screen will be seen as having a resolution of 3600x2000. -- On Windows if the application is not DPI aware, the screen will be seen as having a resolution of 1800x1000 - -By default, if using the glfw backend, applications will be Dpi aware under windows. -Sdl applications are normally not Dpi aware. However HelloImGui makes them Dpi aware when using the sdl backend. - - -## Dpi aware Font scaling - -`HelloImGui::LoadFont()` will load fonts with the correct size, taking into account the DPI scaling. - -If you prefer to use `ImGui::GetIO().Fonts->AddFontFromFileTTF()`, there are two things to know: - -1. You should adjust `ImGui::GetIO().FontGlobalScale`: - -Under windows and linux, it should be is 1: no rescaling should be done by ImGui. -Under macOS and emscripten, it may need to bet set to 0.5 (for example it will be 0.5 if the dpi scaling is 200% -on a macOS retina screen) - -`HelloImGui::ImGuiDefaultFontGlobalScale()` returns the default value that should be stored inside `ImGui::GetIO().FontGlobalScale`. - - -2. You should adjust the font size when loading a font: - -`HelloImGui::DpiFontLoadingFactor()` returns a factor by which you shall multiply your font sizes when loading them. - -`HelloImGui::DpiFontLoadingFactor()` corresponds to: -`DpiWindowSizeFactor() * 1.f / ImGui::GetIO().FontGlobalScale` - -where DpiWindowSizeFactor() is equal to `CurrentScreenPixelPerInch / 96` -under windows and linux, 1 under macOS +@import "dpi_aware.h" {md_id=HandlingScreenHighDPI} diff --git a/src/hello_imgui/doc_params.md b/src/hello_imgui/doc_params.md index c6490bbe..b43855db 100644 --- a/src/hello_imgui/doc_params.md +++ b/src/hello_imgui/doc_params.md @@ -130,6 +130,8 @@ struct RunnerParams // Only useful when multiple rendering backend are compiled and available. RendererBackendType rendererBackendType = RendererBackendType::FirstAvailable; + // --------------- RemoteParams ------------------- + NetImGuiParams remoteParams; // --------------- Settings ------------------- @@ -212,6 +214,7 @@ enum class PlatformBackendType FirstAvailable, Glfw, Sdl, + Null }; // Rendering backend type (OpenGL3, Metal, Vulkan, DirectX11, DirectX12) @@ -224,6 +227,7 @@ enum class RendererBackendType Vulkan, DirectX11, DirectX12, + Null }; ``` @@ -854,11 +858,14 @@ See [dpi_aware.h](https://github.com/pthom/hello_imgui/blob/master/src/hello_img // dpiWindowSizeFactor=2 // fontRenderingScale=0.5 // +// For more information, see the documentation on DPI handling, here: https://pthom.github.io/hello_imgui/book/doc_api.html#handling-screens-with-high-dpi +// struct DpiAwareParams { // `dpiWindowSizeFactor` - // factor by which window size should be multiplied to get a similar - // visible size on different OSes. + // factor by which window size should be multiplied to get a similar + // visible size on different OSes. This affects the size of the window, + // but *not* the size of widgets and text. // In a standard environment (i.e. outside of Hello ImGui), an application with a size of 960x480 pixels, // may have a physical size (in mm or inches) that varies depending on the screen DPI, and the OS. // @@ -873,17 +880,37 @@ struct DpiAwareParams float dpiWindowSizeFactor = 0.0f; // `fontRenderingScale` - // factor (that is either 1 or < 1.) by which fonts glyphs should be - // scaled at rendering time. - // On macOS retina screens, it will be 0.5, since macOS APIs hide - // the real resolution of the screen. + // factor (that is either 1 or < 1.) by which fonts glyphs should be scaled at rendering time. + // On macOS retina screens, it will be 0.5, since macOS APIs hide the real resolution of the screen. + // Changing this value will *not* change the visible font size on the screen, however it will + // affect the size of the loaded glyphs. + // For example, if fontRenderingScale=0.5 (which is the default on a macOS retina screen), + // a font size of 16 will be loaded as if it was 32, and will be rendered at half size. + // This leads to a better rendering quality on some platforms. float fontRenderingScale = 0.0f; // `dpiFontLoadingFactor` // factor by which font size should be multiplied at loading time to get a similar // visible size on different OSes. // The size will be equivalent to a size given for a 96 PPI screen - float DpiFontLoadingFactor() { return dpiWindowSizeFactor / fontRenderingScale;}; + float DpiFontLoadingFactor() { + float r = dpiWindowSizeFactor / fontRenderingScale; + return r; + }; + + // `roDisplayFramebufferScale` + // When rendering, the internal frame buffer size might be bigger than the + // size (in "virtual screen coordinate" pixels) of the window. + // For example: + // - on macOS retina screens, the frame buffer size will be twice the window size + // (and roDisplayFramebufferScale will be 2, 2) + // - on Windows, the frame buffer size will be the same as the window size. + // (since virtual screen coordinate pixels are the same as physical screen pixels on Windows) + // + // This is an output-only value: it will be set by the platform backend + // after it was initialized (any change you make to it at startup will not be used) + // It mirrors the value inside ImGui::GetIO().DisplayFramebufferScale. + ImVec2 roDisplayFramebufferScale = ImVec2(0.f, 0.f); }; // ---------------------------------------------------------------------------- diff --git a/src/hello_imgui/dpi_aware.h b/src/hello_imgui/dpi_aware.h index 22e9be7e..9af21452 100644 --- a/src/hello_imgui/dpi_aware.h +++ b/src/hello_imgui/dpi_aware.h @@ -35,6 +35,8 @@ namespace HelloImGui // dpiWindowSizeFactor=2 // fontRenderingScale=0.5 // +// For more information, see the documentation on DPI handling, here: https://pthom.github.io/hello_imgui/book/doc_api.html#handling-screens-with-high-dpi +// struct DpiAwareParams { // `dpiWindowSizeFactor` @@ -143,3 +145,109 @@ float DpiWindowSizeFactor(); float ImGuiDefaultFontGlobalScale(); } // namespace HelloImGui + +// ---------------------------------------------------------------------------- +// Handling screens with high DPI +// ---------------------------------------------------------------------------- +/* +@@md#HandlingScreenHighDPI + +_Note: This part is relevant only for more advanced usages. If you use `HelloImGui::LoadFont()`, + and always use `HelloImGui::EmToVec2()` to place widgets, you do not need to worry about DPI handling_ + +## OS specificities + +There are several important things to know about high-DPI handling within Hello ImGui and Dear ImGui: + +1. (virtual) screen coordinates vs (physical) pixels +2. DisplayFramebufferScale: Frame buffer size vs window size +3. FontGlobalScale: display-time font scaling factor +4. How to load fonts with the correct size +5. How to get similar window sizes on different OSes/DPI + + +## Screen coordinates + +Screen coordinates are the coordinates you use to place and size windows on the screen. + +**Screen coordinates do not always correspond to physical pixels** + +- On macOS/iOS retina screens, a screen coordinate corresponds typically + to 2x2 physical pixels (but this may vary if you change the display scaling) +- On most Linux distributions, whenever there is a high DPI screen + you can set the display scale. For example if you set the scale to 300%, + then a screen coordinate will correspond to 3x3 physical pixels +- On Windows, there are two possible situations: + - If the application is DPI aware, a screen coordinate corresponds to 1x1 physical pixel, + and you can use the full extent of your screen resolution. + - If the application is not DPI aware, a screen coordinate may correspond to 2x2 physical pixels + (if the display scaling is set to 200% for example). However, the rendering of your application + will be blurry and will not use the full extent of your screen resolution. + - Notes: + - Applications created with HelloImGui are DPI aware by default (when using glfw and sdl backends). + - SDL applications are normally not DPI aware. However, HelloImGui makes them DPI aware. + + +## DisplayFramebufferScale +`DisplayFramebufferScale` is the ratio between the frame buffer size and the window size. + +The frame buffer size is the size of the internal buffer used by the rendering backend. +It might be bigger than the actual window size. +`ImVec2 ImGui::GetIO().DisplayFramebufferScale` is a factor by which the frame buffer size is bigger than the window size. +It is set by the platform backend after it was initialized, and typically reflects the scaling ratio between +physical pixels and screen coordinates. + +Under windows, it will always be (1,1). Under macOS / linux, it will reflect the current display scaling. +It will typically be (2,2) on a macOS retina screen. + +Notes: +- As a convenience, `ImGui::GetIO().DisplayFramebufferScale` is mirrored in `HelloImGui::DpiAwareParams::roDisplayFramebufferScale`. +- You cannot change DisplayFramebufferScale manually, it will be reset at each new frame, by asking the platform backend. + + +## FontGlobalScale + +`ImGui::GetIO().FontGlobalScale` is a factor by which fonts glyphs should be scaled at rendering time. +It is typically 1 on windows, and 0.5 on macOS retina screens. + + +## How to load fonts with the correct size + +### Using HelloImGui::LoadFont + +[`HelloImGui::LoadFont()`](https://pthom.github.io/hello_imgui/book/doc_api.html#load-fonts) will load fonts + with the correct size, taking into account the DPI scaling. + +### Using Dear ImGui's AddFontFromFileTTF(): +`ImGui::GetIO().Fonts->AddFontFromFileTTF()` loads a font with a given size, in *physical pixels*. + +If for example, DisplayFramebufferScale is (2,2), and you load a font with a size of 16, it will by default be rendered + with size of 16 *virtual screen coordinate pixels* (i.e. 32 physical pixels). This will lead to blurry text. +To solve this, you should load your font with a size of 16 *virtual screen coordinate pixels* (i.e. 32 physical pixels), +and set `ImGui::GetIO().FontGlobalScale` to 0.5. + +Helpers if using `ImGui::GetIO().Fonts->AddFontFromFileTTF()`: +- `HelloImGui::ImGuiDefaultFontGlobalScale()` returns the default value that should be stored inside `ImGui::GetIO().FontGlobalScale`. +- `HelloImGui::DpiFontLoadingFactor()` returns a factor by which you shall multiply your font sizes when loading them. + + +## Reproducible physical window sizes (in mm or inches) + +### Using HelloImGui +Simply specify a window size that corresponds to theoretical 96 PPI screen (inside `RunnerParams.appWindowParams.windowGeometry.size`) + +### Using your own code to create the backend window +If you prefer to create the window by yourself, its physical size in millimeters may vary widely, +depending on the OS and the current screen DPI setting. +Typically under Windows, your window may appear to be very small if your screen is high DPI. + +To get a similar window size on different OSes/DPI, you should multiply the window size by `HelloImGui::DpiWindowSizeFactor()`. + +Note: DpiWindowSizeFactor() is equal to `CurrentScreenPixelPerInch / 96` under windows and linux, and always 1 under macOS. + +## Fine tune DPI Handling + +See [`HelloImGui::DpiAwareParams`](https://pthom.github.io/hello_imgui/book/doc_params.html#dpi-aware-params) +for more information on how to fine tune DPI handling when using Hello ImGui. +@@md +*/