1 /*
2 Copyright © 2013 Kurt Rinnert
3 Copyright © 2013 Igor Paliychuk
4 Copyright © 2014 Henrik Andersson
5 Copyright © 2014-2016 Justin Jacobs
6
7 This file is part of FLARE.
8
9 FLARE is free software: you can redistribute it and/or modify it under the terms
10 of the GNU General Public License as published by the Free Software Foundation,
11 either version 3 of the License, or (at your option) any later version.
12
13 FLARE is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 FLARE. If not, see http://www.gnu.org/licenses/
19 */
20
21 #include <SDL_image.h>
22
23 #include <iostream>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "CursorManager.h"
30 #include "EngineSettings.h"
31 #include "IconManager.h"
32 #include "InputState.h"
33 #include "MessageEngine.h"
34 #include "ModManager.h"
35 #include "Platform.h"
36 #include "SharedResources.h"
37 #include "Settings.h"
38
39 #include "SDLSoftwareRenderDevice.h"
40 #include "SDLFontEngine.h"
41
SDLSoftwareImage(RenderDevice * _device)42 SDLSoftwareImage::SDLSoftwareImage(RenderDevice *_device)
43 : Image(_device)
44 , surface(NULL) {
45 }
46
~SDLSoftwareImage()47 SDLSoftwareImage::~SDLSoftwareImage() {
48 if (surface)
49 SDL_FreeSurface(surface);
50 }
51
getWidth() const52 int SDLSoftwareImage::getWidth() const {
53 return surface ? surface->w : 0;
54 }
55
getHeight() const56 int SDLSoftwareImage::getHeight() const {
57 return surface ? surface->h : 0;
58 }
59
fillWithColor(const Color & color)60 void SDLSoftwareImage::fillWithColor(const Color& color) {
61 if (!surface) return;
62
63 SDL_FillRect(surface, NULL, MapRGBA(color.r, color.g, color.b, color.a));
64 }
65
66 /*
67 * Set the pixel at (x, y) to the given value
68 * NOTE: The surface must be locked before calling this!
69 *
70 * Source: SDL Documentation
71 * http://www.libsdl.org/docs/html/guidevideo.html
72 */
drawPixel(int x,int y,const Color & color)73 void SDLSoftwareImage::drawPixel(int x, int y, const Color& color) {
74 if (!surface) return;
75
76 if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight())
77 return;
78
79 Uint32 pixel = MapRGBA(color.r, color.g, color.b, color.a);
80
81 int bpp = surface->format->BytesPerPixel;
82 /* Here p is the address to the pixel we want to set */
83 Uint8 *p = static_cast<Uint8*>(surface->pixels) + y * surface->pitch + x * bpp;
84
85 if (SDL_MUSTLOCK(surface)) {
86 SDL_LockSurface(surface);
87 }
88 switch(bpp) {
89 case 1:
90 *p = static_cast<Uint8>(pixel);
91 break;
92
93 case 2:
94 *(reinterpret_cast<Uint16*>(p)) = static_cast<Uint16>(pixel);
95 break;
96
97 case 3:
98 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
99 p[0] = (pixel >> 16) & 0xff;
100 p[1] = (pixel >> 8) & 0xff;
101 p[2] = pixel & 0xff;
102 #else
103 p[0] = pixel & 0xff;
104 p[1] = (pixel >> 8) & 0xff;
105 p[2] = (pixel >> 16) & 0xff;
106 #endif
107 break;
108
109 case 4:
110 *(reinterpret_cast<Uint32*>(p)) = pixel;
111 break;
112 }
113 if (SDL_MUSTLOCK(surface)) {
114 SDL_UnlockSurface(surface);
115 }
116 }
117
drawLine(int x0,int y0,int x1,int y1,const Color & color)118 void SDLSoftwareImage::drawLine(int x0, int y0, int x1, int y1, const Color& color) {
119 const int dx = abs(x1-x0);
120 const int dy = abs(y1-y0);
121 const int sx = x0 < x1 ? 1 : -1;
122 const int sy = y0 < y1 ? 1 : -1;
123 int err = dx-dy;
124
125 int max_width = getWidth();
126 int max_height = getHeight();
127
128 do {
129 //skip draw if outside screen
130 if (x0 > 0 && y0 > 0 && x0 < max_width && y0 < max_height) {
131 this->drawPixel(x0,y0,color);
132 }
133
134 int e2 = 2*err;
135 if (e2 > -dy) {
136 err = err - dy;
137 x0 = x0 + sx;
138 }
139 if (e2 < dx) {
140 err = err + dx;
141 y0 = y0 + sy;
142 }
143 }
144 while(x0 != x1 || y0 != y1);
145 }
146
147
MapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)148 Uint32 SDLSoftwareImage::MapRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
149 if (!surface) return 0;
150 return SDL_MapRGBA(surface->format, r, g, b, a);
151 }
152
153 /**
154 * Resizes an image
155 * Deletes the original image and returns a pointer to the resized version
156 */
resize(int width,int height)157 Image* SDLSoftwareImage::resize(int width, int height) {
158 if(!surface || width <= 0 || height <= 0)
159 return NULL;
160
161 SDLSoftwareImage *scaled = new SDLSoftwareImage(device);
162
163 if (scaled) {
164 scaled->surface = SDL_CreateRGBSurface(surface->flags, width, height,
165 surface->format->BitsPerPixel,
166 surface->format->Rmask,
167 surface->format->Gmask,
168 surface->format->Bmask,
169 surface->format->Amask);
170
171 if (scaled->surface) {
172 SDL_BlitScaled(surface, NULL, scaled->surface, NULL);
173
174 // delete the old image and return the new one
175 this->unref();
176 return scaled;
177 }
178 else {
179 delete scaled;
180 }
181 }
182
183 return NULL;
184 }
185
SDLSoftwareRenderDevice()186 SDLSoftwareRenderDevice::SDLSoftwareRenderDevice()
187 : screen(NULL)
188 , window(NULL)
189 , renderer(NULL)
190 , texture(NULL)
191 , titlebar_icon(NULL)
192 , title(NULL)
193 , background_color(0) {
194 Utils::logInfo("RenderDevice: Using SDLSoftwareRenderDevice (software, SDL 2, %s)", SDL_GetCurrentVideoDriver());
195
196 fullscreen = settings->fullscreen;
197 hwsurface = settings->hwsurface;
198 vsync = settings->vsync;
199 texture_filter = settings->texture_filter;
200
201 min_screen.x = eset->resolutions.min_screen_w;
202 min_screen.y = eset->resolutions.min_screen_h;
203
204 SDL_DisplayMode desktop;
205 if (SDL_GetDesktopDisplayMode(0, &desktop) == 0) {
206 // we only support display #0
207 Utils::logInfo("RenderDevice: %d display(s), using display 0 (%dx%d @ %dhz)", SDL_GetNumVideoDisplays(), desktop.w, desktop.h, desktop.refresh_rate);
208 }
209
210 // we store the gamma when launching the game in case we need to reset it
211 // these are initilized to 0 since we set them properly with SDL_GetWindowGammaRamp() later
212 for (int i = 0; i < 256; ++i) {
213 gamma_r[i] = 0;
214 gamma_g[i] = 0;
215 gamma_b[i] = 0;
216 }
217 }
218
createContextInternal()219 int SDLSoftwareRenderDevice::createContextInternal() {
220 if (settings->safe_video) {
221 settings->safe_video = false;
222 Utils::logInfo("RenderDevice: Safe mode is enabled. Using minimum video settings.");
223 settings->fullscreen = false;
224 settings->hwsurface = false;
225 settings->vsync = false;
226 settings->texture_filter = false;
227 settings->screen_w = eset->resolutions.min_screen_w;
228 settings->screen_h = eset->resolutions.min_screen_h;
229 }
230
231 bool settings_changed = ((fullscreen != settings->fullscreen && destructive_fullscreen) ||
232 hwsurface != settings->hwsurface ||
233 vsync != settings->vsync ||
234 texture_filter != settings->texture_filter ||
235 ignore_texture_filter != eset->resolutions.ignore_texture_filter);
236
237 Uint32 w_flags = 0;
238 Uint32 r_flags = 0;
239 int window_w = settings->screen_w;
240 int window_h = settings->screen_h;
241
242 if (settings->fullscreen) {
243 w_flags = w_flags | SDL_WINDOW_FULLSCREEN_DESKTOP;
244
245 // make the window the same size as the desktop resolution
246 SDL_DisplayMode desktop;
247 if (SDL_GetDesktopDisplayMode(0, &desktop) == 0) {
248 window_w = desktop.w;
249 window_h = desktop.h;
250 }
251 }
252 else if (fullscreen && is_initialized) {
253 // if the game was previously in fullscreen, resize the window when returning to windowed mode
254 window_w = eset->resolutions.min_screen_w;
255 window_h = eset->resolutions.min_screen_h;
256 }
257
258 w_flags = w_flags | SDL_WINDOW_RESIZABLE;
259
260 if (settings->hwsurface) {
261 r_flags = r_flags | SDL_RENDERER_ACCELERATED;
262 }
263 else {
264 r_flags = r_flags | SDL_RENDERER_SOFTWARE;
265 settings->vsync = false; // can't have software mode & vsync at the same time
266 }
267 if (settings->vsync) r_flags = r_flags | SDL_RENDERER_PRESENTVSYNC;
268
269 if (settings_changed || !is_initialized) {
270 destroyContext();
271
272 window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, w_flags);
273 if (window) {
274 renderer = SDL_CreateRenderer(window, -1, r_flags);
275 if (renderer) {
276 if (settings->texture_filter && !eset->resolutions.ignore_texture_filter)
277 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
278 else
279 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
280
281 windowResize();
282 }
283
284 SDL_SetWindowMinimumSize(window, eset->resolutions.min_screen_w, eset->resolutions.min_screen_h);
285 // setting minimum size might move the window, so set position again
286 SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
287 }
288
289 if (window && renderer && screen && texture) {
290 if (!is_initialized) {
291 // save the system gamma levels if we just created the window
292 SDL_GetWindowGammaRamp(window, gamma_r, gamma_g, gamma_b);
293 Utils::logInfo("RenderDevice: Window size is %dx%d", settings->screen_w, settings->screen_h);
294 }
295
296 fullscreen = settings->fullscreen;
297 hwsurface = settings->hwsurface;
298 vsync = settings->vsync;
299 texture_filter = settings->texture_filter;
300 ignore_texture_filter = eset->resolutions.ignore_texture_filter;
301 is_initialized = true;
302
303 Utils::logInfo("RenderDevice: Fullscreen=%d, Hardware surfaces=%d, Vsync=%d, Texture Filter=%d", fullscreen, hwsurface, vsync, texture_filter);
304
305 #if SDL_VERSION_ATLEAST(2, 0, 4)
306 SDL_GetDisplayDPI(0, &ddpi, 0, 0);
307 Utils::logInfo("RenderDevice: Display DPI is %f", ddpi);
308 #else
309 Utils::logError("RenderDevice: The SDL version used to compile Flare does not support SDL_GetDisplayDPI(). The virtual_dpi setting will be ignored.");
310 #endif
311 }
312 }
313
314 if (is_initialized) {
315 // update minimum window size if it has changed
316 if (min_screen.x != eset->resolutions.min_screen_w || min_screen.y != eset->resolutions.min_screen_h) {
317 min_screen.x = eset->resolutions.min_screen_w;
318 min_screen.y = eset->resolutions.min_screen_h;
319 SDL_SetWindowMinimumSize(window, eset->resolutions.min_screen_w, eset->resolutions.min_screen_h);
320 SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
321 }
322
323 windowResize();
324
325 // update title bar text and icon
326 updateTitleBar();
327
328 // load persistent resources
329 delete icons;
330 icons = new IconManager();
331 delete curs;
332 curs = new CursorManager();
333
334 if (settings->change_gamma)
335 setGamma(settings->gamma);
336 else {
337 resetGamma();
338 settings->change_gamma = false;
339 settings->gamma = 1.0;
340 }
341 }
342
343 return (is_initialized ? 0 : -1);
344 }
345
createContextError()346 void SDLSoftwareRenderDevice::createContextError() {
347 Utils::logError("SDLSoftwareRenderDevice: createContext() failed: %s", SDL_GetError());
348 Utils::logErrorDialog("SDLSoftwareRenderDevice: createContext() failed: %s", SDL_GetError());
349 }
350
render(Renderable & r,Rect & dest)351 int SDLSoftwareRenderDevice::render(Renderable& r, Rect& dest) {
352 SDL_Rect src = r.src;
353 SDL_Rect _dest = dest;
354
355 SDL_Surface *surface = static_cast<SDLSoftwareImage *>(r.image)->surface;
356
357 if (r.blend_mode == Renderable::BLEND_ADD) {
358 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_ADD);
359 }
360 else { // Renderable::BLEND_NORMAL
361 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
362 }
363
364 SDL_SetSurfaceColorMod(surface, r.color_mod.r, r.color_mod.g, r.color_mod.b);
365 SDL_SetSurfaceAlphaMod(surface, r.alpha_mod);
366
367 return SDL_BlitSurface(surface, &src, screen, &_dest);
368 }
369
render(Sprite * r)370 int SDLSoftwareRenderDevice::render(Sprite *r) {
371 if (r == NULL) {
372 return -1;
373 }
374
375 if ( !localToGlobal(r) ) {
376 return -1;
377 }
378
379 SDL_Rect src = m_clip;
380 SDL_Rect dest = m_dest;
381
382 SDL_Surface *surface = static_cast<SDLSoftwareImage *>(r->getGraphics())->surface;
383 SDL_SetSurfaceColorMod(surface, r->color_mod.r, r->color_mod.g, r->color_mod.b);
384 SDL_SetSurfaceAlphaMod(surface, r->alpha_mod);
385
386 return SDL_BlitSurface(surface, &src, screen, &dest);
387 }
388
renderToImage(Image * src_image,Rect & src,Image * dest_image,Rect & dest)389 int SDLSoftwareRenderDevice::renderToImage(Image* src_image, Rect& src, Image* dest_image, Rect& dest) {
390 if (!src_image || !dest_image) return -1;
391
392 SDL_Rect _src = src;
393 SDL_Rect _dest = dest;
394
395 return SDL_BlitSurface(static_cast<SDLSoftwareImage *>(src_image)->surface, &_src,
396 static_cast<SDLSoftwareImage *>(dest_image)->surface, &_dest);
397 }
398
renderTextToImage(FontStyle * font_style,const std::string & text,const Color & color,bool blended)399 Image* SDLSoftwareRenderDevice::renderTextToImage(FontStyle* font_style, const std::string& text, const Color& color, bool blended) {
400 SDLSoftwareImage *image = new SDLSoftwareImage(this);
401 if (!image) return NULL;
402
403 SDL_Color _color = color;
404
405 if (blended)
406 image->surface = TTF_RenderUTF8_Blended(static_cast<SDLFontStyle *>(font_style)->ttfont, text.c_str(), _color);
407 else
408 image->surface = TTF_RenderUTF8_Solid(static_cast<SDLFontStyle *>(font_style)->ttfont, text.c_str(), _color);
409
410 if (image->surface)
411 return image;
412
413 delete image;
414 return NULL;
415 }
416
drawPixel(int x,int y,const Color & color)417 void SDLSoftwareRenderDevice::drawPixel(int x, int y, const Color& color) {
418 Uint32 pixel = MapRGBA(color.r, color.g, color.b, color.a);
419
420 int bpp = screen->format->BytesPerPixel;
421 /* Here p is the address to the pixel we want to set */
422 Uint8 *p = static_cast<Uint8*>(screen->pixels) + y * screen->pitch + x * bpp;
423
424 if (SDL_MUSTLOCK(screen)) {
425 SDL_LockSurface(screen);
426 }
427 switch(bpp) {
428 case 1:
429 *p = static_cast<Uint8>(pixel);
430 break;
431
432 case 2:
433 *(reinterpret_cast<Uint16*>(p)) = static_cast<Uint16>(pixel);
434 break;
435
436 case 3:
437 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
438 p[0] = (pixel >> 16) & 0xff;
439 p[1] = (pixel >> 8) & 0xff;
440 p[2] = pixel & 0xff;
441 #else
442 p[0] = pixel & 0xff;
443 p[1] = (pixel >> 8) & 0xff;
444 p[2] = (pixel >> 16) & 0xff;
445 #endif
446 break;
447
448 case 4:
449 *(reinterpret_cast<Uint32*>(p)) = pixel;
450 break;
451 }
452 if (SDL_MUSTLOCK(screen)) {
453 SDL_UnlockSurface(screen);
454 }
455
456 return;
457 }
458
drawLine(int x0,int y0,int x1,int y1,const Color & color)459 void SDLSoftwareRenderDevice::drawLine(int x0, int y0, int x1, int y1, const Color& color) {
460 const int dx = abs(x1-x0);
461 const int dy = abs(y1-y0);
462 const int sx = x0 < x1 ? 1 : -1;
463 const int sy = y0 < y1 ? 1 : -1;
464 int err = dx-dy;
465
466 do {
467 //skip draw if outside screen
468 if (x0 > 0 && y0 > 0 && x0 < settings->view_w && y0 < settings->view_h) {
469 this->drawPixel(x0,y0,color);
470 }
471
472 int e2 = 2*err;
473 if (e2 > -dy) {
474 err = err - dy;
475 x0 = x0 + sx;
476 }
477 if (e2 < dx) {
478 err = err + dx;
479 y0 = y0 + sy;
480 }
481 }
482 while(x0 != x1 || y0 != y1);
483 }
484
drawRectangle(const Point & p0,const Point & p1,const Color & color)485 void SDLSoftwareRenderDevice::drawRectangle(const Point& p0, const Point& p1, const Color& color) {
486 if (SDL_MUSTLOCK(screen)) {
487 SDL_LockSurface(screen);
488 }
489 this->drawLine(p0.x, p0.y, p1.x, p0.y, color);
490 this->drawLine(p1.x, p0.y, p1.x, p1.y, color);
491 this->drawLine(p0.x, p0.y, p0.x, p1.y, color);
492 this->drawLine(p0.x, p1.y, p1.x, p1.y, color);
493 if (SDL_MUSTLOCK(screen)) {
494 SDL_UnlockSurface(screen);
495 }
496 }
497
blankScreen()498 void SDLSoftwareRenderDevice::blankScreen() {
499 SDL_FillRect(screen, NULL, background_color);
500 return;
501 }
502
commitFrame()503 void SDLSoftwareRenderDevice::commitFrame() {
504 SDL_UpdateTexture(texture, NULL, screen->pixels, screen->pitch);
505 SDL_RenderClear(renderer);
506 SDL_RenderCopy(renderer, texture, NULL, NULL);
507 SDL_RenderPresent(renderer);
508 inpt->window_resized = false;
509
510 return;
511 }
512
destroyContext()513 void SDLSoftwareRenderDevice::destroyContext() {
514 resetGamma();
515
516 // we need to free all loaded graphics as they may be tied to the current context
517 RenderDevice::cacheRemoveAll();
518 reload_graphics = true;
519
520 if (icons) {
521 delete icons;
522 icons = NULL;
523 }
524 if (curs) {
525 delete curs;
526 curs = NULL;
527 }
528 if (title) {
529 free(title);
530 title = NULL;
531 }
532 if (titlebar_icon) {
533 SDL_FreeSurface(titlebar_icon);
534 titlebar_icon = NULL;
535 }
536 if (screen) {
537 SDL_FreeSurface(screen);
538 screen = NULL;
539 }
540 if (texture) {
541 SDL_DestroyTexture(texture);
542 texture = NULL;
543 }
544 if (renderer) {
545 SDL_DestroyRenderer(renderer);
546 renderer = NULL;
547 }
548 if (window) {
549 SDL_DestroyWindow(window);
550 window = NULL;
551 }
552
553 return;
554 }
555
MapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)556 Uint32 SDLSoftwareRenderDevice::MapRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
557 return SDL_MapRGBA(screen->format, r, g, b, a);
558 }
559
560 /**
561 * create blank surface
562 * based on example: http://www.libsdl.org/docs/html/sdlcreatergbsurface.html
563 */
createImage(int width,int height)564 Image *SDLSoftwareRenderDevice::createImage(int width, int height) {
565
566 SDLSoftwareImage *image = new SDLSoftwareImage(this);
567
568 if (!image)
569 return NULL;
570
571 Uint32 rmask, gmask, bmask, amask;
572 setSDL_RGBA(&rmask, &gmask, &bmask, &amask);
573
574 image->surface = SDL_CreateRGBSurface(0, width, height, BITS_PER_PIXEL, rmask, gmask, bmask, amask);
575
576 if(image->surface == NULL) {
577 Utils::logError("SDLSoftwareRenderDevice: CreateRGBSurface failed: %s", SDL_GetError());
578 delete image;
579 return NULL;
580 }
581
582 // optimize
583 SDL_Surface *cleanup = image->surface;
584 image->surface = SDL_ConvertSurfaceFormat(cleanup, SDL_PIXELFORMAT_ARGB8888, 0);
585 SDL_FreeSurface(cleanup);
586
587 return image;
588 }
589
setGamma(float g)590 void SDLSoftwareRenderDevice::setGamma(float g) {
591 Uint16 ramp[256];
592 SDL_CalculateGammaRamp(g, ramp);
593 SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
594 }
595
resetGamma()596 void SDLSoftwareRenderDevice::resetGamma() {
597 SDL_SetWindowGammaRamp(window, gamma_r, gamma_g, gamma_b);
598 }
599
updateTitleBar()600 void SDLSoftwareRenderDevice::updateTitleBar() {
601 if (title) free(title);
602 if (titlebar_icon) SDL_FreeSurface(titlebar_icon);
603
604 if (!window) return;
605
606 title = Utils::strdup(msg->get(eset->misc.window_title));
607 titlebar_icon = IMG_Load(mods->locate("images/logo/icon.png").c_str());
608
609 if (title) SDL_SetWindowTitle(window, title);
610 if (titlebar_icon) SDL_SetWindowIcon(window, titlebar_icon);
611 }
612
loadImage(const std::string & filename,int error_type)613 Image *SDLSoftwareRenderDevice::loadImage(const std::string& filename, int error_type) {
614 // lookup image in cache
615 Image *img;
616 img = cacheLookup(filename);
617 if (img != NULL) return img;
618
619 // load image
620 SDLSoftwareImage *image;
621 image = NULL;
622 SDL_Surface *cleanup = IMG_Load(mods->locate(filename).c_str());
623 if(!cleanup) {
624 if (error_type != ERROR_NONE)
625 Utils::logError("SDLSoftwareRenderDevice: Couldn't load image: '%s'. %s", filename.c_str(), IMG_GetError());
626
627 if (error_type == ERROR_EXIT) {
628 Utils::logErrorDialog("SDLSoftwareRenderDevice: Couldn't load image: '%s'.\n%s", filename.c_str(), IMG_GetError());
629 mods->resetModConfig();
630 Utils::Exit(1);
631 }
632
633 return NULL;
634 }
635 else {
636 image = new SDLSoftwareImage(this);
637 image->surface = SDL_ConvertSurfaceFormat(cleanup, SDL_PIXELFORMAT_ARGB8888, 0);
638 SDL_FreeSurface(cleanup);
639 }
640
641 // store image to cache
642 cacheStore(filename, image);
643 return image;
644 }
645
setSDL_RGBA(Uint32 * rmask,Uint32 * gmask,Uint32 * bmask,Uint32 * amask)646 void SDLSoftwareRenderDevice::setSDL_RGBA(Uint32 *rmask, Uint32 *gmask, Uint32 *bmask, Uint32 *amask) {
647 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
648 *rmask = 0xff000000;
649 *gmask = 0x00ff0000;
650 *bmask = 0x0000ff00;
651 *amask = 0x000000ff;
652 #else
653 *rmask = 0x000000ff;
654 *gmask = 0x0000ff00;
655 *bmask = 0x00ff0000;
656 *amask = 0xff000000;
657 #endif
658 }
659
getWindowSize(short unsigned * screen_w,short unsigned * screen_h)660 void SDLSoftwareRenderDevice::getWindowSize(short unsigned *screen_w, short unsigned *screen_h) {
661 int w,h;
662 SDL_GetWindowSize(window, &w, &h);
663 *screen_w = static_cast<unsigned short>(w);
664 *screen_h = static_cast<unsigned short>(h);
665 }
666
windowResize()667 void SDLSoftwareRenderDevice::windowResize() {
668 windowResizeInternal();
669
670 SDL_RenderSetLogicalSize(renderer, settings->view_w, settings->view_h);
671
672 if (texture) SDL_DestroyTexture(texture);
673 if (screen) SDL_FreeSurface(screen);
674
675 Uint32 rmask, gmask, bmask, amask;
676 int bpp = static_cast<int>(BITS_PER_PIXEL);
677 SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ARGB8888, &bpp, &rmask, &gmask, &bmask, &amask);
678 screen = SDL_CreateRGBSurface(0, settings->view_w, settings->view_h, bpp, rmask, gmask, bmask, amask);
679 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, settings->view_w, settings->view_h);
680
681 settings->updateScreenVars();
682 }
683
setBackgroundColor(Color color)684 void SDLSoftwareRenderDevice::setBackgroundColor(Color color) {
685 background_color = SDL_MapRGBA(screen->format, color.r, color.g, color.b, 255);
686 }
687
setFullscreen(bool enable_fullscreen)688 void SDLSoftwareRenderDevice::setFullscreen(bool enable_fullscreen) {
689 if (!destructive_fullscreen) {
690 if (enable_fullscreen) {
691 if (platform.fullscreen_bypass) {
692 platform.setFullscreen(true);
693 }
694 else {
695 SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
696 }
697 fullscreen = true;
698 }
699 else if (fullscreen) {
700 if (platform.fullscreen_bypass) {
701 platform.setFullscreen(false);
702 }
703 else {
704 SDL_SetWindowFullscreen(window, 0);
705
706 // restore window to the default size
707 SDL_SetWindowMinimumSize(window, eset->resolutions.min_screen_w, eset->resolutions.min_screen_h);
708 SDL_SetWindowSize(window, eset->resolutions.min_screen_w, eset->resolutions.min_screen_h);
709 windowResize();
710 // setting minimum size might move the window, so set position again
711 SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
712 }
713 fullscreen = false;
714 }
715 windowResize();
716 }
717 }
718
getRefreshRate()719 unsigned short SDLSoftwareRenderDevice::getRefreshRate() {
720 SDL_DisplayMode mode;
721 SDL_GetCurrentDisplayMode(0, &mode);
722 return static_cast<unsigned short>(mode.refresh_rate);
723 }
724
725