Moved some aspect ratio calculations into video/util.cpp
[supertux.git] / src / video / util.cpp
1 //  SuperTux
2 //  Copyright (C) 2014 Ingo Ruhnke <grumbel@gmx.de>
3 //
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.
8 //
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.
13 //
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/>.
16
17 #include "video/util.hpp"
18
19 #include <algorithm>
20
21 #include "math/size.hpp"
22 #include "math/vector.hpp"
23
24 namespace {
25
26 inline Size
27 apply_pixel_aspect_ratio_pre(const Size& window_size, float pixel_aspect_ratio)
28 {
29   if (true)
30   {
31     return Size(window_size.width * pixel_aspect_ratio,
32                 window_size.height);
33   }
34   else
35   {
36     return Size(window_size.width,
37                 window_size.height * pixel_aspect_ratio);
38   }
39 }
40
41 inline void
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)
44 {
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;
49
50   out_viewport.w *= transform.x;
51   out_viewport.h *= transform.y;
52
53   out_scale.x = scale * transform.x;
54   out_scale.y = scale * transform.y;
55
56 }
57
58 inline float
59 calculate_scale(const Size& min_size, const Size& max_size,
60                       const Size& window_size,
61                       float magnification)
62 {
63   float scale = magnification;
64   if (scale == 0.0f) // magic value
65   {
66     scale = 1.0f;
67
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)
71     {
72       scale = std::max(static_cast<float>(window_size.width) / max_size.width,
73                        static_cast<float>(window_size.height) / max_size.height);
74     }
75
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)
79     {
80       scale = std::min(static_cast<float>(window_size.width) / min_size.width,
81                        static_cast<float>(window_size.height) / min_size.height);
82     }
83   }
84
85   return scale;
86 }
87
88 inline SDL_Rect
89 calculate_viewport(const Size& max_size, const Size& window_size, float scale)
90 {
91   SDL_Rect viewport;
92
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));
97
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);
101
102   return viewport;
103 }
104
105 } // namespace
106
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,
110                         Vector& out_scale,
111                         Size& out_logical_size,
112                         SDL_Rect& out_viewport)
113 {
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);
117
118   float scale = calculate_scale(min_size, max_size, window_size, magnification);
119
120   // Calculate the new viewport size
121   out_viewport = calculate_viewport(max_size, window_size, scale);
122
123   out_logical_size.width = static_cast<int>(out_viewport.w / scale);
124   out_logical_size.height = static_cast<int>(out_viewport.h / scale);
125
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);
129 }
130
131 float calculate_pixel_aspect_ratio(const Size& source, const Size& target)
132 {
133   float source_aspect = 16.0f / 9.0f; // random guess
134   if (source != Size(0, 0))
135   {
136     source_aspect =
137       static_cast<float>(source.width) /
138       static_cast<float>(source.height);
139   }
140
141   float target_aspect =
142     static_cast<float>(target.width) /
143     static_cast<float>(target.height);
144
145   return target_aspect / source_aspect;
146 }
147
148 /* EOF */