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