#include "video/drawing_request.hpp"
#include "video/gl/gl_surface_data.hpp"
#include "video/gl/gl_texture.hpp"
+#include "video/util.hpp"
+
#define LIGHTMAP_DIV 5
#ifdef GL_VERSION_ES_CM_1_0
apply_video_mode(screen_size, g_config->use_fullscreen);
- if (target_aspect > 1.0f)
- {
- SCREEN_WIDTH = static_cast<int>(screen_size.width * (target_aspect / desktop_aspect));
- SCREEN_HEIGHT = static_cast<int>(screen_size.height);
- }
- else
- {
- SCREEN_WIDTH = static_cast<int>(screen_size.width);
- SCREEN_HEIGHT = static_cast<int>(screen_size.height * (target_aspect / desktop_aspect));
- }
-
Size max_size(1280, 800);
Size min_size(640, 480);
- if (g_config->magnification == 0.0f) // Magic value that means 'minfill'
- {
- // This scales SCREEN_WIDTH/SCREEN_HEIGHT so that they never excede
- // max_size.width/max_size.height resp. min_size.width/min_size.height
- if (SCREEN_WIDTH > max_size.width || SCREEN_HEIGHT > max_size.height)
- {
- float scale1 = float(max_size.width)/SCREEN_WIDTH;
- float scale2 = float(max_size.height)/SCREEN_HEIGHT;
- float scale = (scale1 < scale2) ? scale1 : scale2;
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH * scale);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * scale);
- }
- else if (SCREEN_WIDTH < min_size.width || SCREEN_HEIGHT < min_size.height)
- {
- float scale1 = float(min_size.width)/SCREEN_WIDTH;
- float scale2 = float(min_size.height)/SCREEN_HEIGHT;
- float scale = (scale1 < scale2) ? scale1 : scale2;
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH * scale);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * scale);
- }
+ Vector scale;
+ Size logical_size;
+ calculate_viewport(min_size, max_size,
+ screen_size,
+ target_aspect / desktop_aspect, g_config->magnification,
+ scale,
+ logical_size,
+ viewport);
- viewport.x = 0;
- viewport.y = 0;
- viewport.w = screen_size.width;
- viewport.h = screen_size.height;
+ SCREEN_WIDTH = logical_size.width;
+ SCREEN_HEIGHT = logical_size.height;
- glViewport(viewport.x, viewport.y, viewport.w, viewport.h);
- }
- else
+ if (viewport.x != 0 || viewport.y != 0)
{
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH / g_config->magnification);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT / g_config->magnification);
-
- // This works by adding black borders around the screen to limit
- // SCREEN_WIDTH/SCREEN_HEIGHT to max_size.width/max_size.height
- Size new_size = screen_size;
-
- if (SCREEN_WIDTH > max_size.width)
- {
- new_size.width = static_cast<int>((float) new_size.width * float(max_size.width)/SCREEN_WIDTH);
- SCREEN_WIDTH = static_cast<int>(max_size.width);
- }
-
- if (SCREEN_HEIGHT > max_size.height)
- {
- new_size.height = static_cast<int>((float) new_size.height * float(max_size.height)/SCREEN_HEIGHT);
- SCREEN_HEIGHT = static_cast<int>(max_size.height);
- }
-
// Clear both buffers so that we get a clean black border without junk
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
-
- viewport.x = std::max(0, (screen_size.width - new_size.width) / 2);
- viewport.y = std::max(0, (screen_size.height - new_size.height) / 2);
- viewport.w = std::min(new_size.width, screen_size.width);
- viewport.h = std::min(new_size.height, screen_size.height);
-
- glViewport(viewport.x, viewport.y, viewport.w, viewport.h);
}
+ glViewport(viewport.x, viewport.y, viewport.w, viewport.h);
+
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#include <stdexcept>
#include "SDL2/SDL_video.h"
+#include "video/util.hpp"
+
SDLRenderer::SDLRenderer() :
window(),
renderer(),
Renderer::instance_ = this;
SDL_DisplayMode mode;
- SDL_GetCurrentDisplayMode(0, &mode);
+ SDL_GetDesktopDisplayMode(0, &mode);
desktop_size = Size(mode.w, mode.h);
log_info << "creating SDLRenderer" << std::endl;
viewport.x = 0;
viewport.y = 0;
- viewport.w = SCREEN_WIDTH;
- viewport.h = SCREEN_HEIGHT;
+ viewport.w = width;
+ viewport.h = height;
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
if(texture_manager == 0)
texture_manager = new TextureManager();
+ g_config->window_size = Size(width, height);
apply_config();
}
}
void
-SDLRenderer::apply_config()
+SDLRenderer::apply_video_mode()
{
- if (false)
- {
- log_info << "Applying Config:"
- << "\n Desktop: " << desktop_size.width << "x" << desktop_size.height
- << "\n Window: " << g_config->window_size
- << "\n FullRes: " << g_config->fullscreen_size
- << "\n Aspect: " << g_config->aspect_size
- << "\n Magnif: " << g_config->magnification
- << std::endl;
- }
-
- float target_aspect = static_cast<float>(desktop_size.width) / static_cast<float>(desktop_size.height);
- if (g_config->aspect_size != Size(0, 0))
- {
- target_aspect = float(g_config->aspect_size.width) / float(g_config->aspect_size.height);
- }
-
- float desktop_aspect = 4.0f / 3.0f; // random default fallback guess
- if (desktop_size.width != -1 && desktop_size.height != -1)
- {
- desktop_aspect = float(desktop_size.width) / float(desktop_size.height);
- }
-
- Size screen_size;
-
- // Get the screen width
- if (g_config->use_fullscreen)
- {
- screen_size = g_config->fullscreen_size;
- desktop_aspect = float(screen_size.width) / float(screen_size.height);
- }
- else
- {
- screen_size = g_config->window_size;
- }
-
if (!g_config->use_fullscreen)
{
SDL_SetWindowFullscreen(window, 0);
}
}
- if (target_aspect > 1.0f)
+}
+
+void
+SDLRenderer::apply_viewport()
+{
+ // calculate the aspect ratio
+ float target_aspect = static_cast<float>(desktop_size.width) / static_cast<float>(desktop_size.height);
+ if (g_config->aspect_size != Size(0, 0))
{
- SCREEN_WIDTH = static_cast<int>(screen_size.width * (target_aspect / desktop_aspect));
- SCREEN_HEIGHT = static_cast<int>(screen_size.height);
+ target_aspect = float(g_config->aspect_size.width) / float(g_config->aspect_size.height);
}
- else
+
+ float desktop_aspect = 4.0f / 3.0f; // random default fallback guess
+ if (desktop_size.width != -1 && desktop_size.height != -1)
{
- SCREEN_WIDTH = static_cast<int>(screen_size.width);
- SCREEN_HEIGHT = static_cast<int>(screen_size.height * (target_aspect / desktop_aspect));
+ desktop_aspect = float(desktop_size.width) / float(desktop_size.height);
}
- Size max_size(1280, 800);
- Size min_size(640, 480);
+ Size screen_size;
- if (g_config->magnification == 0.0f) // Magic value that means 'minfill'
+ // Get the screen width
+ if (g_config->use_fullscreen)
{
- float magnification = 1.0f;
-
- // This scales SCREEN_WIDTH/SCREEN_HEIGHT so that they never excede
- // max_size.width/max_size.height resp. min_size.width/min_size.height
- if (SCREEN_WIDTH > max_size.width || SCREEN_HEIGHT > max_size.height)
- {
- float scale1 = float(max_size.width)/SCREEN_WIDTH;
- float scale2 = float(max_size.height)/SCREEN_HEIGHT;
- magnification = (scale1 < scale2) ? scale1 : scale2;
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH * magnification);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * magnification);
- }
- else if (SCREEN_WIDTH < min_size.width || SCREEN_HEIGHT < min_size.height)
- {
- float scale1 = float(min_size.width)/SCREEN_WIDTH;
- float scale2 = float(min_size.height)/SCREEN_HEIGHT;
- magnification = (scale1 < scale2) ? scale1 : scale2;
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH * magnification);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT * magnification);
- }
-
- viewport.x = 0;
- viewport.y = 0;
- viewport.w = screen_size.width;
- viewport.h = screen_size.height;
-
- SDL_RenderSetScale(renderer, 1.0f, 1.0f);
- SDL_RenderSetViewport(renderer, &viewport);
- SDL_RenderSetScale(renderer, magnification, magnification);
+ screen_size = g_config->fullscreen_size;
+ desktop_aspect = float(screen_size.width) / float(screen_size.height);
}
else
{
- SCREEN_WIDTH = static_cast<int>(SCREEN_WIDTH / g_config->magnification);
- SCREEN_HEIGHT = static_cast<int>(SCREEN_HEIGHT / g_config->magnification);
+ screen_size = g_config->window_size;
+ }
- // This works by adding black borders around the screen to limit
- // SCREEN_WIDTH/SCREEN_HEIGHT to max_size.width/max_size.height
- Size new_size = screen_size;
+ // calculate the viewport
+ Size max_size(1280, 800);
+ Size min_size(640, 480);
- if (SCREEN_WIDTH > max_size.width)
- {
- new_size.width = static_cast<int>((float) new_size.width * float(max_size.width)/SCREEN_WIDTH);
- SCREEN_WIDTH = static_cast<int>(max_size.width);
- }
+ // FIXME: don't do this, save window size
+ Size window_size;
+ SDL_GetWindowSize(window, &window_size.width, &window_size.height);
- if (SCREEN_HEIGHT > max_size.height)
- {
- new_size.height = static_cast<int>((float) new_size.height * float(max_size.height)/SCREEN_HEIGHT);
- SCREEN_HEIGHT = static_cast<int>(max_size.height);
- }
+ Vector scale;
+ Size logical_size;
+ calculate_viewport(min_size, max_size, window_size,
+ target_aspect / desktop_aspect,
+ g_config->magnification,
+ scale, logical_size, viewport);
+
+ SCREEN_WIDTH = logical_size.width;
+ SCREEN_HEIGHT = logical_size.height;
+ if (viewport.x != 0 || viewport.y != 0)
+ {
// Clear the screen to avoid garbage in unreachable areas after we
// reset the coordinate system
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_RenderClear(renderer);
+ }
- viewport.x = std::max(0, (screen_size.width - new_size.width) / 2);
- viewport.y = std::max(0, (screen_size.height - new_size.height) / 2);
- viewport.w = std::min(new_size.width, screen_size.width);
- viewport.h = std::min(new_size.height, screen_size.height);
+ SDL_RenderSetScale(renderer, 1.0f, 1.0f);
+ SDL_RenderSetViewport(renderer, &viewport);
+ SDL_RenderSetScale(renderer, scale.x, scale.y);
+}
- SDL_RenderSetScale(renderer, 1.0f, 1.0f);
- SDL_RenderSetViewport(renderer, &viewport);
- SDL_RenderSetScale(renderer, g_config->magnification, g_config->magnification);
- }
+void
+SDLRenderer::apply_config()
+{
+ apply_video_mode();
+ apply_viewport();
}
Vector
Vector to_logical(int physical_x, int physical_y);
void set_gamma(float gamma);
SDL_Window* get_window() const { return window; }
-
SDL_Renderer* get_sdl_renderer() const { return renderer; };
private:
+ void apply_video_mode();
+ void apply_viewport();
+
+private:
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Rect viewport;
--- /dev/null
+// SuperTux
+// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmx.de>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "video/util.hpp"
+
+#include <algorithm>
+
+#include "math/size.hpp"
+#include "math/vector.hpp"
+
+namespace {
+
+inline Size
+apply_pixel_aspect_ratio_pre(const Size& window_size, float pixel_aspect_ratio)
+{
+ if (pixel_aspect_ratio < 1.0f)
+ {
+ return Size(window_size.width * pixel_aspect_ratio,
+ window_size.height);
+ }
+ else
+ {
+ return Size(window_size.width,
+ window_size.height * pixel_aspect_ratio);
+ }
+}
+
+inline void
+apply_pixel_aspect_ratio_post(const Size& real_window_size, const Size& window_size, float scale,
+ SDL_Rect& out_viewport, Vector& out_scale)
+{
+ Vector transform(static_cast<float>(real_window_size.width) / window_size.width,
+ static_cast<float>(real_window_size.height) / window_size.height);
+ out_viewport.x *= transform.x;
+ out_viewport.y *= transform.y;
+
+ out_viewport.w *= transform.x;
+ out_viewport.h *= transform.y;
+
+ out_scale.x = scale * transform.x;
+ out_scale.y = scale * transform.y;
+
+}
+
+inline float
+calculate_scale(const Size& min_size, const Size& max_size,
+ const Size& window_size,
+ float magnification)
+{
+ float scale = magnification;
+ if (scale == 0.0f) // magic value
+ {
+ scale = 1.0f;
+
+ // Find the minimum magnification that is needed to fill the screen
+ if (window_size.width > max_size.width ||
+ window_size.height > max_size.height)
+ {
+ scale = std::max(static_cast<float>(window_size.width) / max_size.width,
+ static_cast<float>(window_size.height) / max_size.height);
+ }
+
+ // If the resulting area would violate min_size, scale it down
+ if (window_size.width / scale < min_size.width ||
+ window_size.height / scale < min_size.height)
+ {
+ scale = std::min(static_cast<float>(window_size.width) / min_size.width,
+ static_cast<float>(window_size.height) / min_size.height);
+ }
+ }
+
+ return scale;
+}
+
+inline SDL_Rect
+calculate_viewport(const Size& max_size, const Size& window_size, float scale)
+{
+ SDL_Rect viewport;
+
+ viewport.w = std::min(window_size.width,
+ static_cast<int>(scale * max_size.width));
+ viewport.h = std::min(window_size.height,
+ static_cast<int>(scale * max_size.height));
+
+ // Center the viewport in the window
+ viewport.x = std::max(0, (window_size.width - viewport.w) / 2);
+ viewport.y = std::max(0, (window_size.height - viewport.h) / 2);
+
+ return viewport;
+}
+
+} // namespace
+
+void calculate_viewport(const Size& min_size, const Size& max_size,
+ const Size& real_window_size,
+ float pixel_aspect_ratio, float magnification,
+ Vector& out_scale,
+ Size& out_logical_size,
+ SDL_Rect& out_viewport)
+{
+ // Transform the real window_size by the aspect ratio, then do
+ // calculations on that virtual window_size
+ Size window_size = apply_pixel_aspect_ratio_pre(real_window_size, pixel_aspect_ratio);
+
+ float scale = calculate_scale(min_size, max_size, window_size, magnification);
+
+ // Calculate the new viewport size
+ out_viewport = calculate_viewport(max_size, window_size, scale);
+
+ out_logical_size.width = static_cast<int>(out_viewport.w / scale);
+ out_logical_size.height = static_cast<int>(out_viewport.h / scale);
+
+ // Transform the virtual window_size back into real window coordinates
+ apply_pixel_aspect_ratio_post(real_window_size, window_size, scale,
+ out_viewport, out_scale);
+}
+
+/* EOF */
--- /dev/null
+// SuperTux
+// Copyright (C) 2013 Ingo Ruhnke <grumbel@gmx.de>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef HEADER_SUPERTUX_VIDEO_UTIL_HPP
+#define HEADER_SUPERTUX_VIDEO_UTIL_HPP
+
+#include "SDL_rect.h"
+
+class Size;
+class Vector;
+
+void calculate_viewport(const Size& min_size, const Size& max_size,
+ const Size& real_window_size,
+ float pixel_aspect_ratio, float magnification,
+ Vector& out_scale,
+ Size& out_logical_size,
+ SDL_Rect& out_viewport);
+
+#endif
+
+/* EOF */