| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
1 |
/* |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
2 |
Copyright (c) 2025 Poul Sander |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
3 |
|
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
4 |
Permission is hereby granted, free of charge, to any person |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
5 |
obtaining a copy of this software and associated documentation files |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
6 |
(the "Software"), to deal in the Software without restriction, |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
7 |
including without limitation the rights to use, copy, modify, merge, |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
8 |
publish, distribute, sublicense, and/or sell copies of the Software, |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
9 |
and to permit persons to whom the Software is furnished to do so, |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
10 |
subject to the following conditions: |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
11 |
|
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
12 |
The above copyright notice and this permission notice shall be |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
13 |
included in all copies or substantial portions of the Software. |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
14 |
|
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
15 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
16 |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
17 |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
18 |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
19 |
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
20 |
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
21 |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
22 |
SOFTWARE. |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
23 |
*/ |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
24 |
|
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
25 |
#pragma once |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
26 |
#include <algorithm> |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
27 |
#include "SDL.h" |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
28 |
|
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
29 |
|
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
30 |
namespace sago { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
31 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
32 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
33 |
* @brief Provides coordinate transformation between logical and physical screen coordinates. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
34 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
35 |
* This class helps create resolution-independent layouts by defining coordinates in a fixed |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
36 |
* "logical" resolution and automatically converting them to the actual "physical" screen size. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
37 |
* It maintains aspect ratio by adding letterboxing/pillarboxing margins when needed. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
38 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
39 |
* Key concepts: |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
40 |
* - Logical coordinates: Fixed coordinate system you design for (e.g., 1920x1080) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
41 |
* - Physical coordinates: Actual screen/window size (e.g., 1280x720, 3840x2160, etc.) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
42 |
* - Scale factor: Calculated to fit logical size into physical size while preserving aspect ratio |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
43 |
* - Margins: Black bars added to maintain aspect ratio (letterboxing/pillarboxing) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
44 |
* - Tile alignment: As long as tiles are resized with LogicalToPhysical, they will align correctly. No gaps or overlaps. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
45 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
46 |
* Example usage: |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
47 |
* @code |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
48 |
* // Design your UI for 1920x1080 |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
49 |
* SagoLogicalResize resize(1920, 1080); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
50 |
* resize.SetPhysicalSize(window_width, window_height); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
51 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
52 |
* // Draw at logical position (100, 100) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
53 |
* int phys_x, phys_y; |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
54 |
* resize.LogicalToPhysical(100, 100, phys_x, phys_y); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
55 |
* DrawSprite(renderer, phys_x, phys_y); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
56 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
57 |
* // Handle mouse input |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
58 |
* int log_x, log_y; |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
59 |
* resize.PhysicalToLogical(mouse_x, mouse_y, log_x, log_y); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
60 |
* if (log_x > 100 && log_x < 200) { ... } |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
61 |
* @endcode |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
62 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
63 |
class SagoLogicalResize { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
64 |
public: |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
65 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
66 |
* @brief Default constructor with minimal 1x1 logical size. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
67 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
68 |
SagoLogicalResize() : logical_width_(1), logical_height_(1), physical_width_(1), physical_height_(1) { |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
69 |
SetScaleFactor(); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
70 |
} |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
71 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
72 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
73 |
* @brief Constructor with specified logical resolution. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
74 |
* @param logical_width The width of the logical coordinate system (minimum 1) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
75 |
* @param logical_height The height of the logical coordinate system (minimum 1) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
76 |
*/ |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
77 |
SagoLogicalResize(int logical_width, int logical_height) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
78 |
: logical_width_(std::max(1, logical_width)), logical_height_(std::max(1, logical_height)), physical_width_(1), physical_height_(1) { |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
79 |
SetScaleFactor(); |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
80 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
81 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
82 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
83 |
* @brief Updates the physical (actual) screen size and recalculates scaling. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
84 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
85 |
* Call this when the window is resized or when initializing the physical display size. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
86 |
* This recalculates the scale factor and margins to fit the logical size into the physical size. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
87 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
88 |
* @param physical_width The actual width of the screen/window (minimum 1) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
89 |
* @param physical_height The actual height of the screen/window (minimum 1) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
90 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
91 |
void SetPhysicalSize(int physical_width, int physical_height) { |
| 62b87fe3 |
Poul Sander |
2025-03-04 20:16 |
92 |
//Physical size must be at least 1. Less than 1 is not drawn anyway and it prevents division by zero. |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
93 |
physical_width_ = std::max(1, physical_width); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
94 |
physical_height_ = std::max(1, physical_height); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
95 |
SetScaleFactor(); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
96 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
97 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
98 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
99 |
* @brief Converts logical coordinates to physical screen coordinates. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
100 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
101 |
* This applies the scale factor and adds the appropriate margins. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
102 |
* Use this to convert positions where you want to draw elements on screen. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
103 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
104 |
* @param logical_x The x coordinate in logical space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
105 |
* @param logical_y The y coordinate in logical space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
106 |
* @param physical_x Output: the x coordinate in physical screen space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
107 |
* @param physical_y Output: the y coordinate in physical screen space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
108 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
109 |
void LogicalToPhysical(int logical_x, int logical_y, int& physical_x, int& physical_y) const { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
110 |
physical_x = logical_x; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
111 |
physical_y = logical_y; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
112 |
LogicalToPhysical(&physical_x, &physical_y); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
113 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
114 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
115 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
116 |
* @brief Converts logical coordinates to physical screen coordinates (pointer version). |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
117 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
118 |
* This applies the scale factor and adds the appropriate margins. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
119 |
* Null pointers are safely ignored. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
120 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
121 |
* @param x Pointer to x coordinate (will be converted in place), can be null |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
122 |
* @param y Pointer to y coordinate (will be converted in place), can be null |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
123 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
124 |
void LogicalToPhysical(int* x, int* y) const { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
125 |
if (x) { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
126 |
*x = *x * scale_factor_ + left_margin_; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
127 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
128 |
if (y) { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
129 |
*y = *y * scale_factor_ + top_margin_; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
130 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
131 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
132 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
133 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
134 |
* @brief Converts a logical rectangle to physical screen coordinates. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
135 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
136 |
* This converts both the position AND size of a rectangle. The rectangle |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
137 |
* is transformed in place. Use this for converting areas/regions rather than |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
138 |
* just single points. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
139 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
140 |
* Note: This properly handles the size conversion by converting the bottom-right |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
141 |
* corner and calculating the new width/height from the difference. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
142 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
143 |
* @param inout The rectangle in logical coordinates (input), converted to physical coordinates (output) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
144 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
145 |
void LogicalToPhysical(SDL_Rect& inout) const { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
146 |
SDL_Rect input = inout; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
147 |
LogicalToPhysical(&inout.x, &inout.y); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
148 |
LogicalToPhysical(input.x + input.w + 1, input.y + input.h + 1, inout.w, inout.h); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
149 |
inout.w -= inout.x - 1; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
150 |
inout.h -= inout.y - 1; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
151 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
152 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
153 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
154 |
* @brief Converts physical screen coordinates to logical coordinates. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
155 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
156 |
* Use this to convert mouse input or other physical positions back to your |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
157 |
* logical coordinate system for hit detection and input handling. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
158 |
* This removes margins and applies inverse scaling. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
159 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
160 |
* @param physical_x The x coordinate in physical screen space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
161 |
* @param physical_y The y coordinate in physical screen space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
162 |
* @param logical_x Output: the x coordinate in logical space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
163 |
* @param logical_y Output: the y coordinate in logical space |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
164 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
165 |
void PhysicalToLogical(int physical_x, int physical_y, int& logical_x, int& logical_y) const { |
| 931a61e9 |
Poul Sander |
2025-03-05 20:35 |
166 |
logical_x = (physical_x - left_margin_) / scale_factor_; |
| 931a61e9 |
Poul Sander |
2025-03-05 20:35 |
167 |
logical_y = (physical_y - top_margin_) / scale_factor_; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
168 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
169 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
170 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
171 |
* @brief Gets the top margin (letterboxing/pillarboxing offset). |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
172 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
173 |
* This is the black bar size at the top when the aspect ratio requires vertical margins. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
174 |
* Useful for debugging or custom rendering that needs to know the drawable area. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
175 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
176 |
* @return The top margin in physical pixels |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
177 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
178 |
int GetTopMargin() const { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
179 |
return top_margin_; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
180 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
181 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
182 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
183 |
* @brief Gets the left margin (letterboxing/pillarboxing offset). |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
184 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
185 |
* This is the black bar size on the left when the aspect ratio requires horizontal margins. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
186 |
* Useful for debugging or custom rendering that needs to know the drawable area. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
187 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
188 |
* @return The left margin in physical pixels |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
189 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
190 |
int GetLeftMargin() const { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
191 |
return left_margin_; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
192 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
193 |
|
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
194 |
private: |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
195 |
/** |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
196 |
* @brief Calculates the scale factor and margins based on current logical and physical sizes. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
197 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
198 |
* The scale factor is chosen to fit the logical size into the physical size while |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
199 |
* maintaining aspect ratio. The margins center the content on screen. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
200 |
* |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
201 |
* Scale factor = min(physical_width/logical_width, physical_height/logical_height) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
202 |
* This ensures the content fits in both dimensions without distortion. |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
203 |
*/ |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
204 |
void SetScaleFactor() { |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
205 |
scale_factor_ = std::min(physical_width_ / logical_width_, physical_height_ / logical_height_); |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
206 |
left_margin_ = (physical_width_ - logical_width_ * scale_factor_) / 2; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
207 |
top_margin_ = (physical_height_ - logical_height_ * scale_factor_) / 2; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
208 |
} |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
209 |
|
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
210 |
double scale_factor_; ///< Multiplier to convert logical size to physical size |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
211 |
int top_margin_; ///< Vertical offset for centering (letterboxing) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
212 |
int left_margin_; ///< Horizontal offset for centering (pillarboxing) |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
213 |
double logical_width_; ///< Width of the logical coordinate system |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
214 |
double logical_height_; ///< Height of the logical coordinate system |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
215 |
double physical_width_; ///< Actual width of the screen/window |
| 1de972a7 |
Poul Sander |
2025-11-11 20:23 |
216 |
double physical_height_; ///< Actual height of the screen/window |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
217 |
}; |
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
218 |
|
| cb02a4a0 |
Poul Sander |
2025-03-03 21:25 |
219 |
} // namespace sago |