2 // Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "video/util.hpp"
21 #include "math/size.hpp"
22 #include "math/vector.hpp"
27 apply_pixel_aspect_ratio_pre(const Size& window_size, float pixel_aspect_ratio)
31 return Size(window_size.width * pixel_aspect_ratio,
36 return Size(window_size.width,
37 window_size.height * pixel_aspect_ratio);
42 apply_pixel_aspect_ratio_post(const Size& real_window_size, const Size& window_size, float scale,
43 SDL_Rect& out_viewport, Vector& out_scale)
45 Vector transform(static_cast<float>(real_window_size.width) / window_size.width,
46 static_cast<float>(real_window_size.height) / window_size.height);
47 out_viewport.x *= transform.x;
48 out_viewport.y *= transform.y;
50 out_viewport.w *= transform.x;
51 out_viewport.h *= transform.y;
53 out_scale.x = scale * transform.x;
54 out_scale.y = scale * transform.y;
59 calculate_scale(const Size& min_size, const Size& max_size,
60 const Size& window_size,
63 float scale = magnification;
64 if (scale == 0.0f) // magic value
68 // Find the minimum magnification that is needed to fill the screen
69 if (window_size.width > max_size.width ||
70 window_size.height > max_size.height)
72 scale = std::max(static_cast<float>(window_size.width) / max_size.width,
73 static_cast<float>(window_size.height) / max_size.height);
76 // If the resulting area would violate min_size, scale it down
77 if (window_size.width / scale < min_size.width ||
78 window_size.height / scale < min_size.height)
80 scale = std::min(static_cast<float>(window_size.width) / min_size.width,
81 static_cast<float>(window_size.height) / min_size.height);
89 calculate_viewport(const Size& max_size, const Size& window_size, float scale)
93 viewport.w = std::min(window_size.width,
94 static_cast<int>(scale * max_size.width));
95 viewport.h = std::min(window_size.height,
96 static_cast<int>(scale * max_size.height));
98 // Center the viewport in the window
99 viewport.x = std::max(0, (window_size.width - viewport.w) / 2);
100 viewport.y = std::max(0, (window_size.height - viewport.h) / 2);
107 void calculate_viewport(const Size& min_size, const Size& max_size,
108 const Size& real_window_size,
109 float pixel_aspect_ratio, float magnification,
111 Size& out_logical_size,
112 SDL_Rect& out_viewport)
114 // Transform the real window_size by the aspect ratio, then do
115 // calculations on that virtual window_size
116 Size window_size = apply_pixel_aspect_ratio_pre(real_window_size, pixel_aspect_ratio);
118 float scale = calculate_scale(min_size, max_size, window_size, magnification);
120 // Calculate the new viewport size
121 out_viewport = calculate_viewport(max_size, window_size, scale);
123 out_logical_size.width = static_cast<int>(out_viewport.w / scale);
124 out_logical_size.height = static_cast<int>(out_viewport.h / scale);
126 // Transform the virtual window_size back into real window coordinates
127 apply_pixel_aspect_ratio_post(real_window_size, window_size, scale,
128 out_viewport, out_scale);
131 float calculate_pixel_aspect_ratio(const Size& source, const Size& target)
133 float source_aspect = 16.0f / 9.0f; // random guess
134 if (source != Size(0, 0))
137 static_cast<float>(source.width) /
138 static_cast<float>(source.height);
141 float target_aspect =
142 static_cast<float>(target.width) /
143 static_cast<float>(target.height);
145 return target_aspect / source_aspect;