2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 // Updated by GiBy 2013 for SDL2 <giby_the_kid@yahoo.fr>
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "video/sdl/sdl_renderer.hpp"
20 #include "util/log.hpp"
21 #include "video/drawing_request.hpp"
22 #include "video/sdl/sdl_surface_data.hpp"
23 #include "video/sdl/sdl_texture.hpp"
24 #include "video/sdl/sdl_painter.hpp"
31 #include "SDL2/SDL_video.h"
33 #include "video/util.hpp"
35 SDLRenderer::SDLRenderer() :
43 if (SDL_GetDesktopDisplayMode(0, &mode) != 0)
45 log_warning << "Couldn't get desktop display mode: " << SDL_GetError() << std::endl;
49 m_desktop_size = Size(mode.w, mode.h);
52 log_info << "creating SDLRenderer" << std::endl;
53 int width = g_config->window_size.width;
54 int height = g_config->window_size.height;
56 int flags = SDL_WINDOW_RESIZABLE;
57 if(g_config->use_fullscreen)
59 if (g_config->fullscreen_size == Size(0, 0))
61 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
62 width = g_config->window_size.width;
63 height = g_config->window_size.height;
67 flags |= SDL_WINDOW_FULLSCREEN;
68 width = g_config->fullscreen_size.width;
69 height = g_config->fullscreen_size.height;
74 SCREEN_HEIGHT = height;
79 m_viewport.h = height;
81 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
83 int ret = SDL_CreateWindowAndRenderer(width, height, flags,
84 &m_window, &m_renderer);
87 std::stringstream msg;
88 msg << "Couldn't set video mode (" << width << "x" << height
89 << "): " << SDL_GetError();
90 throw std::runtime_error(msg.str());
93 SDL_RendererInfo info;
94 if (SDL_GetRendererInfo(m_renderer, &info) != 0)
96 log_warning << "Couldn't get RendererInfo: " << SDL_GetError() << std::endl;
100 log_info << "SDL_Renderer: " << info.name << std::endl;
101 log_info << "SDL_RendererFlags: " << std::endl;
102 if (info.flags & SDL_RENDERER_SOFTWARE) { log_info << " SDL_RENDERER_SOFTWARE" << std::endl; }
103 if (info.flags & SDL_RENDERER_ACCELERATED) { log_info << " SDL_RENDERER_ACCELERATED" << std::endl; }
104 if (info.flags & SDL_RENDERER_PRESENTVSYNC) { log_info << " SDL_RENDERER_PRESENTVSYNC" << std::endl; }
105 if (info.flags & SDL_RENDERER_TARGETTEXTURE) { log_info << " SDL_RENDERER_TARGETTEXTURE" << std::endl; }
106 log_info << "Texture Formats: " << std::endl;
107 for(size_t i = 0; i < info.num_texture_formats; ++i)
109 log_info << " " << SDL_GetPixelFormatName(info.texture_formats[i]) << std::endl;
111 log_info << "Max Texture Width: " << info.max_texture_width << std::endl;
112 log_info << "Max Texture Height: " << info.max_texture_height << std::endl;
115 g_config->window_size = Size(width, height);
119 SDLRenderer::~SDLRenderer()
121 SDL_DestroyRenderer(m_renderer);
122 SDL_DestroyWindow(m_window);
126 SDLRenderer::start_draw()
128 SDL_RenderSetScale(m_renderer, m_scale.x, m_scale.y);
132 SDLRenderer::end_draw()
137 SDLRenderer::draw_surface(const DrawingRequest& request)
139 SDLPainter::draw_surface(m_renderer, request);
143 SDLRenderer::draw_surface_part(const DrawingRequest& request)
145 SDLPainter::draw_surface_part(m_renderer, request);
149 SDLRenderer::draw_gradient(const DrawingRequest& request)
151 SDLPainter::draw_gradient(m_renderer, request);
155 SDLRenderer::draw_filled_rect(const DrawingRequest& request)
157 SDLPainter::draw_filled_rect(m_renderer, request);
161 SDLRenderer::draw_inverse_ellipse(const DrawingRequest& request)
163 SDLPainter::draw_inverse_ellipse(m_renderer, request);
167 SDLRenderer::do_take_screenshot()
169 // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
172 if (SDL_GetRendererOutputSize(m_renderer, &width, &height) != 0)
174 log_warning << "SDL_GetRenderOutputSize failed: " << SDL_GetError() << std::endl;
178 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
179 Uint32 rmask = 0xff000000;
180 Uint32 gmask = 0x00ff0000;
181 Uint32 bmask = 0x0000ff00;
182 Uint32 amask = 0x000000ff;
184 Uint32 rmask = 0x000000ff;
185 Uint32 gmask = 0x0000ff00;
186 Uint32 bmask = 0x00ff0000;
187 Uint32 amask = 0xff000000;
189 SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32,
190 rmask, gmask, bmask, amask);
193 log_warning << "SDL_CreateRGBSurface failed: " << SDL_GetError() << std::endl;
197 int ret = SDL_RenderReadPixels(m_renderer, NULL,
198 SDL_PIXELFORMAT_ABGR8888,
203 log_warning << "SDL_RenderReadPixels failed: " << SDL_GetError() << std::endl;
208 static const std::string writeDir = PHYSFS_getWriteDir();
209 static const std::string dirSep = PHYSFS_getDirSeparator();
210 static const std::string baseName = "screenshot";
211 static const std::string fileExt = ".bmp";
212 std::string fullFilename;
213 for (int num = 0; num < 1000; num++) {
214 std::ostringstream oss;
216 oss << std::setw(3) << std::setfill('0') << num;
218 std::string fileName = oss.str();
219 fullFilename = writeDir + dirSep + fileName;
220 if (!PHYSFS_exists(fileName.c_str())) {
221 SDL_SaveBMP(surface, fullFilename.c_str());
222 log_info << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
226 log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
235 SDL_RenderPresent(m_renderer);
239 SDLRenderer::resize(int w , int h)
241 g_config->window_size = Size(w, h);
247 SDLRenderer::apply_video_mode()
249 if (!g_config->use_fullscreen)
251 SDL_SetWindowFullscreen(m_window, 0);
255 if (g_config->fullscreen_size.width == 0 &&
256 g_config->fullscreen_size.height == 0)
258 if (SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0)
260 log_warning << "failed to switch to desktop fullscreen mode: "
261 << SDL_GetError() << std::endl;
265 log_info << "switched to desktop fullscreen mode" << std::endl;
270 SDL_DisplayMode mode;
271 mode.format = SDL_PIXELFORMAT_RGB888;
272 mode.w = g_config->fullscreen_size.width;
273 mode.h = g_config->fullscreen_size.height;
274 mode.refresh_rate = g_config->fullscreen_refresh_rate;
277 if (SDL_SetWindowDisplayMode(m_window, &mode) != 0)
279 log_warning << "failed to set display mode: "
280 << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": "
281 << SDL_GetError() << std::endl;
285 if (SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN) != 0)
287 log_warning << "failed to switch to fullscreen mode: "
288 << mode.w << "x" << mode.h << "@" << mode.refresh_rate << ": "
289 << SDL_GetError() << std::endl;
293 log_info << "switched to fullscreen mode: "
294 << mode.w << "x" << mode.h << "@" << mode.refresh_rate << std::endl;
302 SDLRenderer::apply_viewport()
304 Size target_size = (g_config->use_fullscreen && g_config->fullscreen_size != Size(0, 0)) ?
305 g_config->fullscreen_size :
306 g_config->window_size;
308 float pixel_aspect_ratio = 1.0f;
309 if (g_config->aspect_size != Size(0, 0))
311 pixel_aspect_ratio = calculate_pixel_aspect_ratio(m_desktop_size,
312 g_config->aspect_size);
314 else if (g_config->use_fullscreen)
316 pixel_aspect_ratio = calculate_pixel_aspect_ratio(m_desktop_size,
320 // calculate the viewport
321 Size max_size(1280, 800);
322 Size min_size(640, 480);
325 calculate_viewport(min_size, max_size,
328 g_config->magnification,
329 m_scale, logical_size, m_viewport);
331 SCREEN_WIDTH = logical_size.width;
332 SCREEN_HEIGHT = logical_size.height;
334 if (m_viewport.x != 0 || m_viewport.y != 0)
336 // Clear the screen to avoid garbage in unreachable areas after we
337 // reset the coordinate system
338 SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255);
339 SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_NONE);
340 SDL_RenderClear(m_renderer);
341 SDL_RenderPresent(m_renderer);
342 SDL_RenderClear(m_renderer);
345 // SetViewport() works in scaled screen coordinates, so we have to
346 // reset it to 1.0, 1.0 to get meaningful results
347 SDL_RenderSetScale(m_renderer, 1.0f, 1.0f);
348 SDL_RenderSetViewport(m_renderer, &m_viewport);
349 SDL_RenderSetScale(m_renderer, m_scale.x, m_scale.y);
353 SDLRenderer::apply_config()
360 SDLRenderer::to_logical(int physical_x, int physical_y)
362 return Vector(static_cast<float>(physical_x - m_viewport.x) * SCREEN_WIDTH / m_viewport.w,
363 static_cast<float>(physical_y - m_viewport.y) * SCREEN_HEIGHT / m_viewport.h);
367 SDLRenderer::set_gamma(float gamma)
370 SDL_CalculateGammaRamp(gamma, ramp);
371 SDL_SetWindowGammaRamp(m_window, ramp, ramp, ramp);