Skip to content

Commit

Permalink
Improve doc / Dpi Params
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Apr 11, 2024
1 parent 48dfbfb commit 9817a93
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 69 deletions.
105 changes: 82 additions & 23 deletions src/hello_imgui/doc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
40 changes: 1 addition & 39 deletions src/hello_imgui/doc_api.src.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}
41 changes: 34 additions & 7 deletions src/hello_imgui/doc_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ struct RunnerParams
// Only useful when multiple rendering backend are compiled and available.
RendererBackendType rendererBackendType = RendererBackendType::FirstAvailable;

// --------------- RemoteParams -------------------
NetImGuiParams remoteParams;


// --------------- Settings -------------------
Expand Down Expand Up @@ -212,6 +214,7 @@ enum class PlatformBackendType
FirstAvailable,
Glfw,
Sdl,
Null
};

// Rendering backend type (OpenGL3, Metal, Vulkan, DirectX11, DirectX12)
Expand All @@ -224,6 +227,7 @@ enum class RendererBackendType
Vulkan,
DirectX11,
DirectX12,
Null
};

```
Expand Down Expand Up @@ -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.
//
Expand All @@ -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);
};

// ----------------------------------------------------------------------------
Expand Down
108 changes: 108 additions & 0 deletions src/hello_imgui/dpi_aware.h
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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
*/

0 comments on commit 9817a93

Please sign in to comment.