X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvideo%2Fsdl%2Fsdl_renderer.cpp;h=86c85f7758d657f5de7c105f189f3bb5c8b4f11e;hb=d8857573c93d23338945424f65a57901bbc390b7;hp=49f1af1ef2e789e305f6b7f6bab8a577c1859e44;hpb=548a198187ef3a45f1d1a27528a9a6d1646691b5;p=supertux.git diff --git a/src/video/sdl/sdl_renderer.cpp b/src/video/sdl/sdl_renderer.cpp index 49f1af1ef..86c85f775 100644 --- a/src/video/sdl/sdl_renderer.cpp +++ b/src/video/sdl/sdl_renderer.cpp @@ -30,16 +30,26 @@ #include #include "SDL2/SDL_video.h" +#include "video/util.hpp" + SDLRenderer::SDLRenderer() : window(), renderer(), - desktop_size() + viewport(), + desktop_size(0, 0), + m_scale(1.0f, 1.0f) { Renderer::instance_ = this; SDL_DisplayMode mode; - SDL_GetCurrentDisplayMode(0, &mode); - desktop_size = Size(mode.w, mode.h); + if (SDL_GetDesktopDisplayMode(0, &mode) != 0) + { + log_warning << "Couldn't get desktop display mode: " << SDL_GetError() << std::endl; + } + else + { + desktop_size = Size(mode.w, mode.h); + } log_info << "creating SDLRenderer" << std::endl; int width = g_config->window_size.width; @@ -48,16 +58,27 @@ SDLRenderer::SDLRenderer() : int flags = SDL_WINDOW_RESIZABLE; if(g_config->use_fullscreen) { - flags |= SDL_WINDOW_FULLSCREEN; - width = g_config->fullscreen_size.width; - height = g_config->fullscreen_size.height; + if (g_config->fullscreen_size == Size(0, 0)) + { + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + width = g_config->window_size.width; + height = g_config->window_size.height; + } + else + { + flags |= SDL_WINDOW_FULLSCREEN; + width = g_config->fullscreen_size.width; + height = g_config->fullscreen_size.height; + } } SCREEN_WIDTH = width; SCREEN_HEIGHT = height; - PHYSICAL_SCREEN_WIDTH = width; - PHYSICAL_SCREEN_HEIGHT = height; + viewport.x = 0; + viewport.y = 0; + viewport.w = width; + viewport.h = height; SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); @@ -80,10 +101,10 @@ SDLRenderer::SDLRenderer() : { log_info << "SDL_Renderer: " << info.name << std::endl; log_info << "SDL_RendererFlags: " << std::endl; - if (info.flags & SDL_RENDERER_SOFTWARE) log_info << " SDL_RENDERER_SOFTWARE" << std::endl; - if (info.flags & SDL_RENDERER_ACCELERATED) log_info << " SDL_RENDERER_ACCELERATED" << std::endl; - if (info.flags & SDL_RENDERER_PRESENTVSYNC) log_info << " SDL_RENDERER_PRESENTVSYNC" << std::endl; - if (info.flags & SDL_RENDERER_TARGETTEXTURE) log_info << " SDL_RENDERER_TARGETTEXTURE" << std::endl; + if (info.flags & SDL_RENDERER_SOFTWARE) { log_info << " SDL_RENDERER_SOFTWARE" << std::endl; } + if (info.flags & SDL_RENDERER_ACCELERATED) { log_info << " SDL_RENDERER_ACCELERATED" << std::endl; } + if (info.flags & SDL_RENDERER_PRESENTVSYNC) { log_info << " SDL_RENDERER_PRESENTVSYNC" << std::endl; } + if (info.flags & SDL_RENDERER_TARGETTEXTURE) { log_info << " SDL_RENDERER_TARGETTEXTURE" << std::endl; } log_info << "Texture Formats: " << std::endl; for(size_t i = 0; i < info.num_texture_formats; ++i) { @@ -96,6 +117,7 @@ SDLRenderer::SDLRenderer() : if(texture_manager == 0) texture_manager = new TextureManager(); + g_config->window_size = Size(width, height); apply_config(); } @@ -106,6 +128,17 @@ SDLRenderer::~SDLRenderer() } void +SDLRenderer::start_draw() +{ + SDL_RenderSetScale(renderer, m_scale.x, m_scale.y); +} + +void +SDLRenderer::end_draw() +{ +} + +void SDLRenderer::draw_surface(const DrawingRequest& request) { SDLPainter::draw_surface(renderer, request); @@ -135,7 +168,7 @@ SDLRenderer::draw_inverse_ellipse(const DrawingRequest& request) SDLPainter::draw_inverse_ellipse(renderer, request); } -void +void SDLRenderer::do_take_screenshot() { // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it? @@ -212,162 +245,127 @@ SDLRenderer::resize(int w , int h) { g_config->window_size = Size(w, h); - PHYSICAL_SCREEN_WIDTH = w; - PHYSICAL_SCREEN_HEIGHT = h; - 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(desktop_size.width) / static_cast(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); } else { - SDL_DisplayMode mode; - mode.format = SDL_PIXELFORMAT_RGB888; - mode.w = g_config->fullscreen_size.width; - mode.h = g_config->fullscreen_size.height; - mode.refresh_rate = g_config->fullscreen_refresh_rate; - mode.driverdata = 0; - - if (SDL_SetWindowDisplayMode(window, &mode) != 0) + if (g_config->fullscreen_size.width == 0 && + g_config->fullscreen_size.height == 0) { - log_warning << "failed to set display mode: " - << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": " - << SDL_GetError() << std::endl; + if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) + { + log_warning << "failed to switch to desktop fullscreen mode: " + << SDL_GetError() << std::endl; + } + else + { + log_info << "switched to desktop fullscreen mode" << std::endl; + } } else { - SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); + SDL_DisplayMode mode; + mode.format = SDL_PIXELFORMAT_RGB888; + mode.w = g_config->fullscreen_size.width; + mode.h = g_config->fullscreen_size.height; + mode.refresh_rate = g_config->fullscreen_refresh_rate; + mode.driverdata = 0; + + if (SDL_SetWindowDisplayMode(window, &mode) != 0) + { + log_warning << "failed to set display mode: " + << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": " + << SDL_GetError() << std::endl; + } + else + { + if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0) + { + log_warning << "failed to switch to fullscreen mode: " + << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": " + << SDL_GetError() << std::endl; + } + else + { + log_info << "switched to fullscreen mode: " + << mode.w << "x" << mode.h << "@" << mode.refresh_rate << std::endl; + } + } } } +} - if (target_aspect > 1.0f) +void +SDLRenderer::apply_viewport() +{ + Size target_size = (g_config->use_fullscreen && g_config->fullscreen_size != Size(0, 0)) ? + g_config->fullscreen_size : + g_config->window_size; + + float pixel_aspect_ratio = 1.0f; + if (g_config->aspect_size != Size(0, 0)) { - SCREEN_WIDTH = static_cast(screen_size.width * (target_aspect / desktop_aspect)); - SCREEN_HEIGHT = static_cast(screen_size.height); + pixel_aspect_ratio = calculate_pixel_aspect_ratio(desktop_size, + g_config->aspect_size); } - else + else if (g_config->use_fullscreen) { - SCREEN_WIDTH = static_cast(screen_size.width); - SCREEN_HEIGHT = static_cast(screen_size.height * (target_aspect / desktop_aspect)); + pixel_aspect_ratio = calculate_pixel_aspect_ratio(desktop_size, + target_size); } + // calculate the viewport 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(SCREEN_WIDTH * scale); - SCREEN_HEIGHT = static_cast(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(SCREEN_WIDTH * scale); - SCREEN_HEIGHT = static_cast(SCREEN_HEIGHT * scale); - } - } - else - { - SCREEN_WIDTH = static_cast(SCREEN_WIDTH / g_config->magnification); - SCREEN_HEIGHT = static_cast(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; + Size logical_size; + calculate_viewport(min_size, max_size, + target_size, + pixel_aspect_ratio, + g_config->magnification, + m_scale, logical_size, viewport); - if (SCREEN_WIDTH > max_size.width) - { - new_size.width = static_cast((float) new_size.width * float(max_size.width)/SCREEN_WIDTH); - SCREEN_WIDTH = static_cast(max_size.width); - } + SCREEN_WIDTH = logical_size.width; + SCREEN_HEIGHT = logical_size.height; - if (SCREEN_HEIGHT > max_size.height) - { - new_size.height = static_cast((float) new_size.height * float(max_size.height)/SCREEN_HEIGHT); - SCREEN_HEIGHT = static_cast(max_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_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); + SDL_RenderClear(renderer); } - // Clear the screen to avoid garbage in unreachable areas after we - // reset the coordinate system - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); - SDL_RenderClear(renderer); - SDL_RenderPresent(renderer); - SDL_RenderClear(renderer); + // SetViewport() works in scaled screen coordinates, so we have to + // reset it to 1.0, 1.0 to get meaningful results + SDL_RenderSetScale(renderer, 1.0f, 1.0f); + SDL_RenderSetViewport(renderer, &viewport); + SDL_RenderSetScale(renderer, m_scale.x, m_scale.y); +} - // This doesn't really do what we want, as it sales the area to fill - // the screen, but seems to be the only way to reset the coordinate - // system and it's "close enough" to what we want, see: - // https://bugzilla.libsdl.org/show_bug.cgi?id=2179 - SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT); +void +SDLRenderer::apply_config() +{ + apply_video_mode(); + apply_viewport(); } Vector -SDLRenderer::to_logical(int physical_x, int physical_y, bool foobar) +SDLRenderer::to_logical(int physical_x, int physical_y) { - if (foobar) - { - // SDL translates coordinates automatically, except for SDL_GetMouseState(), thus foobar - return Vector(physical_x * float(SCREEN_WIDTH) / (PHYSICAL_SCREEN_WIDTH), - physical_y * float(SCREEN_HEIGHT) / (PHYSICAL_SCREEN_HEIGHT)); - } - else - { - // SDL is doing the translation internally, so we have nothing to do - return Vector(physical_x, physical_y); - } + return Vector(static_cast(physical_x - viewport.x) * SCREEN_WIDTH / viewport.w, + static_cast(physical_y - viewport.y) * SCREEN_HEIGHT / viewport.h); } void