Merged drawing code from SDLLightmap and SDLRenderer into helper class SDLPainter
[supertux.git] / src / video / sdl / sdl_renderer.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //      Updated by GiBy 2013 for SDL2 <giby_the_kid@yahoo.fr>
4 //
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.
9 //
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.
14 //
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/>.
17
18 #include "video/sdl/sdl_renderer.hpp"
19
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"
25
26 #include <iomanip>
27 #include <iostream>
28 #include <physfs.h>
29 #include <sstream>
30 #include <stdexcept>
31 #include "SDL2/SDL_video.h"
32
33 SDLRenderer::SDLRenderer() :
34   window(),
35   renderer()
36 {
37   Renderer::instance_ = this;
38
39   log_info << "creating SDLRenderer" << std::endl;
40   int width  = g_config->window_size.width;
41   int height = g_config->window_size.height;
42
43   int flags = SDL_WINDOW_RESIZABLE;
44   if(g_config->use_fullscreen)
45   {
46     flags |= SDL_WINDOW_FULLSCREEN;
47     width  = g_config->fullscreen_size.width;
48     height = g_config->fullscreen_size.height;
49   }
50
51   SCREEN_WIDTH = width;
52   SCREEN_HEIGHT = height;
53
54   PHYSICAL_SCREEN_WIDTH = width;
55   PHYSICAL_SCREEN_HEIGHT = height;
56
57   int ret = SDL_CreateWindowAndRenderer(width, height, flags,
58                                         &window, &renderer);
59
60   if(ret != 0) {
61     std::stringstream msg;
62     msg << "Couldn't set video mode (" << width << "x" << height
63         << "): " << SDL_GetError();
64     throw std::runtime_error(msg.str());
65   }
66
67   SDL_RendererInfo info;
68   if (SDL_GetRendererInfo(renderer, &info) != 0)
69   {
70     log_warning << "Couldn't get RendererInfo: " << SDL_GetError() << std::endl;
71   }
72   else
73   {
74     log_info << "SDL_Renderer: " << info.name << std::endl;
75     log_info << "SDL_RendererFlags: " << std::endl;
76     if (info.flags & SDL_RENDERER_SOFTWARE) log_info << "  SDL_RENDERER_SOFTWARE" << std::endl;
77     if (info.flags & SDL_RENDERER_ACCELERATED) log_info << "  SDL_RENDERER_ACCELERATED" << std::endl;
78     if (info.flags & SDL_RENDERER_PRESENTVSYNC) log_info << "  SDL_RENDERER_PRESENTVSYNC" << std::endl;
79     if (info.flags & SDL_RENDERER_TARGETTEXTURE) log_info << "  SDL_RENDERER_TARGETTEXTURE" << std::endl;
80     log_info << "Texture Formats: " << std::endl;
81     for(size_t i = 0; i < info.num_texture_formats; ++i)
82     {
83       log_info << "  " << SDL_GetPixelFormatName(info.texture_formats[i]) << std::endl;
84     }
85     log_info << "Max Texture Width: " << info.max_texture_width << std::endl;
86     log_info << "Max Texture Height: " << info.max_texture_height << std::endl;
87   }
88
89   if(texture_manager == 0)
90     texture_manager = new TextureManager();
91 }
92
93 SDLRenderer::~SDLRenderer()
94 {
95   SDL_DestroyRenderer(renderer);
96   SDL_DestroyWindow(window);
97 }
98
99 void
100 SDLRenderer::draw_surface(const DrawingRequest& request)
101 {
102   SDLPainter::draw_surface(renderer, request);
103 }
104
105 void
106 SDLRenderer::draw_surface_part(const DrawingRequest& request)
107 {
108   SDLPainter::draw_surface_part(renderer, request);
109 }
110
111 void
112 SDLRenderer::draw_gradient(const DrawingRequest& request)
113 {
114   SDLPainter::draw_gradient(renderer, request);
115 }
116
117 void
118 SDLRenderer::draw_filled_rect(const DrawingRequest& request)
119 {
120   SDLPainter::draw_filled_rect(renderer, request);
121 }
122
123 void
124 SDLRenderer::draw_inverse_ellipse(const DrawingRequest& request)
125 {
126   SDLPainter::draw_inverse_ellipse(renderer, request);
127 }
128
129 void 
130 SDLRenderer::do_take_screenshot()
131 {
132   // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it?
133   int width;
134   int height;
135   if (SDL_GetRendererOutputSize(renderer, &width, &height) != 0)
136   {
137     log_warning << "SDL_GetRenderOutputSize failed: " << SDL_GetError() << std::endl;
138   }
139   else
140   {
141 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
142     Uint32 rmask = 0xff000000;
143     Uint32 gmask = 0x00ff0000;
144     Uint32 bmask = 0x0000ff00;
145     Uint32 amask = 0x000000ff;
146 #else
147     Uint32 rmask = 0x000000ff;
148     Uint32 gmask = 0x0000ff00;
149     Uint32 bmask = 0x00ff0000;
150     Uint32 amask = 0xff000000;
151 #endif
152     SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32,
153                                                 rmask, gmask, bmask, amask);
154     if (!surface)
155     {
156       log_warning << "SDL_CreateRGBSurface failed: " << SDL_GetError() << std::endl;
157     }
158     else
159     {
160       int ret = SDL_RenderReadPixels(renderer, NULL,
161                                      SDL_PIXELFORMAT_ABGR8888,
162                                      surface->pixels,
163                                      surface->pitch);
164       if (ret != 0)
165       {
166         log_warning << "SDL_RenderReadPixels failed: " << SDL_GetError() << std::endl;
167       }
168       else
169       {
170         // save screenshot
171         static const std::string writeDir = PHYSFS_getWriteDir();
172         static const std::string dirSep = PHYSFS_getDirSeparator();
173         static const std::string baseName = "screenshot";
174         static const std::string fileExt = ".bmp";
175         std::string fullFilename;
176         for (int num = 0; num < 1000; num++) {
177           std::ostringstream oss;
178           oss << baseName;
179           oss << std::setw(3) << std::setfill('0') << num;
180           oss << fileExt;
181           std::string fileName = oss.str();
182           fullFilename = writeDir + dirSep + fileName;
183           if (!PHYSFS_exists(fileName.c_str())) {
184             SDL_SaveBMP(surface, fullFilename.c_str());
185             log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl;
186             return;
187           }
188         }
189         log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl;
190       }
191     }
192   }
193 }
194
195 void
196 SDLRenderer::flip()
197 {
198   SDL_RenderPresent(renderer);
199 }
200
201 void
202 SDLRenderer::resize(int w , int h)
203 {
204   SCREEN_WIDTH  = w;
205   SCREEN_HEIGHT = h;
206
207   PHYSICAL_SCREEN_WIDTH = w;
208   PHYSICAL_SCREEN_HEIGHT = h;
209 }
210
211 void
212 SDLRenderer::set_gamma(float gamma)
213 {
214   Uint16 ramp[256];
215   SDL_CalculateGammaRamp(gamma, ramp);
216   SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
217 }
218
219 /* EOF */