Advanced Tutorial on DPI and UI Scaling in Leadwerks 5
Advanced Tutorial on DPI and UI Scaling in Leadwerks 5
This tutorial will provide a detailed, technical explanation of managing System DPI (Dots Per Inch) Scaling for window creation and In-Game UI Scaling for accessibility within the Leadwerks 5 game engine using Lua. This approach ensures your application renders correctly across various monitor resolutions, particularly High DPI displays like $4\text{K}$.
1. System DPI Integration: Window Sizing
The Operating System (OS) uses DPI scaling as a global multiplier for rendering the user interface elements, making them legible on high-resolution screens. In Leadwerks 5, we must retrieve this factor to calculate the appropriate pixel dimensions for our game window.
Technical Concept: Logical vs. Physical Window Size
-
Logical Size (Base): The target resolution for your content (e.g., $1280 \times 720$). This is the resolution you design for.
-
DPI Factor (
_displayScale
): The float value (e.g., $1.25$ for $125\%$ scaling) retrieved from the OS. -
Physical Size (Pixels): The final dimensions of the window on the screen, calculated as $\text{Logical Size} \times \text{DPI Factor}$.
Implementation in the CApp
Object (Initialization)
The CApp:Init()
function performs the crucial step of window dimensioning:
-- CApp:New() local function Init() -- 1. Query the available displays (monitors). _displays = GetDisplays() -- 2. Retrieve the DPI scale factor from the primary display (index 1). -- This function returns the scale set by the OS (e.g., 1.5). _displayScale = _displays[1]:GetScale() -- 3. Calculate the Physical Window Dimensions. -- This scales the logical base resolution to match the OS display settings. local windowWidth = 1280 * _displayScale local windowHeight = 720 * _displayScale _window = CreateWindow("Leadwerks", 0, 0, windowWidth, windowHeight, _displays[1], WINDOW_CENTER | WINDOW_TITLEBAR) -- 4. Framebuffer Creation: The framebuffer's dimensions are automatically -- set to the physical pixel size of the newly created window, -- which is already DPI-scaled. _framebuffer = CreateFramebuffer(_window) -- The _framebuffer.size is now the correct DPI-adjusted resolution used -- for camera setup and UI background sizing. end
Advanced Tutorial on DPI and UI Scaling in Leadwerks 5
This tutorial will provide a detailed, technical explanation of managing System DPI (Dots Per Inch) Scaling for window creation and In-Game UI Scaling for accessibility within the Leadwerks 5 game engine using Lua. This approach ensures your application renders correctly across various monitor resolutions, particularly High DPI displays like $4\text{K}$.
1. System DPI Integration: Window Sizing
The Operating System (OS) uses DPI scaling as a global multiplier for rendering the user interface elements, making them legible on high-resolution screens. In Leadwerks 5, we must retrieve this factor to calculate the appropriate pixel dimensions for our game window.
Technical Concept: Logical vs. Physical Window Size
-
Logical Size (Base): The target resolution for your content (e.g., $1280 \times 720$). This is the resolution you design for.
-
DPI Factor (
_displayScale
): The float value (e.g., $1.25$ for $125\%$ scaling) retrieved from the OS. -
Physical Size (Pixels): The final dimensions of the window on the screen, calculated as $\text{Logical Size} \times \text{DPI Factor}$.
Implementation in the CApp
Object (Initialization)
The CApp:Init()
function performs the crucial step of window dimensioning:
-- CApp:New() local function Init() -- 1. Query the available displays (monitors). _displays = GetDisplays() -- 2. Retrieve the DPI scale factor from the primary display (index 1). -- This function returns the scale set by the OS (e.g., 1.5). _displayScale = _displays[1]:GetScale() -- 3. Calculate the Physical Window Dimensions. -- This scales the logical base resolution to match the OS display settings. local windowWidth = 1280 * _displayScale local windowHeight = 720 * _displayScale _window = CreateWindow("Leadwerks", 0, 0, windowWidth, windowHeight, _displays[1], WINDOW_CENTER | WINDOW_TITLEBAR) -- 4. Framebuffer Creation: The framebuffer's dimensions are automatically -- set to the physical pixel size of the newly created window, -- which is already DPI-scaled. _framebuffer = CreateFramebuffer(_window) -- The _framebuffer.size is now the correct DPI-adjusted resolution used -- for camera setup and UI background sizing. end
Outcome: The game window is created with the exact physical size required to maintain the visual fidelity and scale intended by the user's OS settings.
2. In-Game UI Scaling: Accessibility and Redrawing
While the window is correctly sized, the UI elements are initially drawn based on the raw framebuffer size. We use the $UI:SetScale()$
method to apply a uniform zoom factor to all UI elements, offering accessibility options.
Technical Concept: UI Hierarchy and Coordinate Recalculation
-
UI Root (
_ui
): The primary UI object created with the DPI-adjusted_framebuffer.size
. -
Automatic Scaling: When
$UI:SetScale(factor)$
is called, all child elements (like buttons and labels) automatically inherit this scale factor. -
Manual Recalculation: Top-level panels and containers, whose position is often calculated relative to the screen size (e.g., centered), must be manually redrawn using the new scale factor to maintain correct positioning.
Implementation in the CMenu
Object (Control and Redraw)
The $self:Update()$
function demonstrates the dynamic scaling mechanism triggered by a user input (the SPACE key).
function self:Update() -- ... Event loop if ev.id == EVENT_KEYDOWN and ev.data == KEY_SPACE then -- 1. Apply a new uniform scale factor to the entire UI hierarchy. -- This acts as an accessibility zoom. _ui:SetScale(1.25) local currentScale = _ui:GetScale() -- 2. Recalculate and set the shape for the TOP-LEVEL panel (_pnlMenu). -- Original Coordinates (e.g., 300, 150, 600, 100) are the LOGICAL design values. -- These must be multiplied by the currentScale to correctly adjust the panel's -- physical position and size on the screen. -- Original Position X: _szUi.x / 2 - 300 -- New Position X: (_szUi.x / 2 - 300) * currentScale is INCORRECT. -- We want to scale the OFFSET (300) from the center. _pnlMenu:SetShape( _szUi.x / 2 - 300 * currentScale, -- Scaled X Offset from center _szUi.y - 150 * currentScale, -- Scaled Y Position 600 * currentScale, -- Scaled Width 100 * currentScale -- Scaled Height ) -- NOTE: The button positions within _pnlMenu remain the same (relative), -- but their physical size on screen is scaled by the factor applied to the root UI. end -- ... end
By correctly applying the DPI factor during window creation and managing the UI scale multiplier for top-level containers, we achieve a robust, high-resolution-ready UI system in Leadwerks 5.
-
2
0 Comments
Recommended Comments
There are no comments to display.