1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #define FORBIDDEN_SYMBOL_ALLOW_ALL
24
25 #include "backends/platform/sdl/sdl.h"
26 #include "common/config-manager.h"
27 #include "gui/EventRecorder.h"
28 #include "common/taskbar.h"
29 #include "common/textconsole.h"
30 #include "common/translation.h"
31 #include "common/encoding.h"
32
33 #include "backends/saves/default/default-saves.h"
34
35 // Audio CD support was removed with SDL 2.0
36 #if SDL_VERSION_ATLEAST(2, 0, 0)
37 #include "backends/audiocd/default/default-audiocd.h"
38 #else
39 #include "backends/audiocd/sdl/sdl-audiocd.h"
40 #endif
41
42 #include "backends/events/default/default-events.h"
43 #include "backends/events/sdl/sdl-events.h"
44 #include "backends/mutex/sdl/sdl-mutex.h"
45 #include "backends/timer/sdl/sdl-timer.h"
46 #include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
47 #ifdef USE_OPENGL
48 #include "backends/graphics/openglsdl/openglsdl-graphics.h"
49 #include "graphics/cursorman.h"
50 #endif
51
52 #include <time.h> // for getTimeAndDate()
53
54 #ifdef USE_DETECTLANG
55 #ifndef WIN32
56 #include <locale.h>
57 #endif // !WIN32
58 #endif
59
60 #ifdef USE_SDL_NET
61 #include <SDL_net.h>
62 #endif
63
64 #if SDL_VERSION_ATLEAST(2, 0, 0)
65 #include <SDL_clipboard.h>
66 #endif
67
OSystem_SDL()68 OSystem_SDL::OSystem_SDL()
69 :
70 #ifdef USE_OPENGL
71 _desktopWidth(0),
72 _desktopHeight(0),
73 _graphicsModes(),
74 _graphicsMode(0),
75 _firstGLMode(0),
76 _defaultSDLMode(0),
77 _defaultGLMode(0),
78 #endif
79 _inited(false),
80 _initedSDL(false),
81 #ifdef USE_SDL_NET
82 _initedSDLnet(false),
83 #endif
84 _logger(0),
85 _mixerManager(0),
86 _eventSource(0),
87 _window(0) {
88
89 ConfMan.registerDefault("kbdmouse_speed", 3);
90 ConfMan.registerDefault("joystick_deadzone", 3);
91 }
92
~OSystem_SDL()93 OSystem_SDL::~OSystem_SDL() {
94 SDL_ShowCursor(SDL_ENABLE);
95
96 // Delete the various managers here. Note that the ModularBackend
97 // destructor would also take care of this for us. However, various
98 // of our managers must be deleted *before* we call SDL_Quit().
99 // Hence, we perform the destruction on our own.
100 delete _savefileManager;
101 _savefileManager = 0;
102 if (_graphicsManager) {
103 dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->deactivateManager();
104 }
105 delete _graphicsManager;
106 _graphicsManager = 0;
107 delete _window;
108 _window = 0;
109 delete _eventManager;
110 _eventManager = 0;
111 delete _eventSource;
112 _eventSource = 0;
113 delete _audiocdManager;
114 _audiocdManager = 0;
115 delete _mixerManager;
116 _mixerManager = 0;
117
118 #ifdef ENABLE_EVENTRECORDER
119 // HACK HACK HACK
120 // This is nasty.
121 delete g_eventRec.getTimerManager();
122 #else
123 delete _timerManager;
124 #endif
125
126 _timerManager = 0;
127 delete _mutexManager;
128 _mutexManager = 0;
129
130 delete _logger;
131 _logger = 0;
132
133 #ifdef USE_SDL_NET
134 if (_initedSDLnet) SDLNet_Quit();
135 #endif
136
137 SDL_Quit();
138 }
139
init()140 void OSystem_SDL::init() {
141 // Initialize SDL
142 initSDL();
143
144 #if !SDL_VERSION_ATLEAST(2, 0, 0)
145 // Enable unicode support if possible
146 SDL_EnableUNICODE(1);
147 #endif
148
149 // Disable OS cursor
150 SDL_ShowCursor(SDL_DISABLE);
151
152 if (!_logger)
153 _logger = new Backends::Log::Log(this);
154
155 if (_logger) {
156 Common::WriteStream *logFile = createLogFile();
157 if (logFile)
158 _logger->open(logFile);
159 }
160
161
162 // Creates the early needed managers, if they don't exist yet
163 // (we check for this to allow subclasses to provide their own).
164 if (_mutexManager == 0)
165 _mutexManager = new SdlMutexManager();
166
167 if (_window == 0)
168 _window = new SdlWindow();
169
170 #if defined(USE_TASKBAR)
171 if (_taskbarManager == 0)
172 _taskbarManager = new Common::TaskbarManager();
173 #endif
174
175 }
176
hasFeature(Feature f)177 bool OSystem_SDL::hasFeature(Feature f) {
178 #if SDL_VERSION_ATLEAST(2, 0, 0)
179 if (f == kFeatureClipboardSupport) return true;
180 #endif
181 if (f == kFeatureJoystickDeadzone || f == kFeatureKbdMouseSpeed) {
182 bool joystickSupportEnabled = ConfMan.getInt("joystick_num") >= 0;
183 return joystickSupportEnabled;
184 }
185 return ModularBackend::hasFeature(f);
186 }
187
initBackend()188 void OSystem_SDL::initBackend() {
189 // Check if backend has not been initialized
190 assert(!_inited);
191
192 #if SDL_VERSION_ATLEAST(2, 0, 0)
193 const char *sdlDriverName = SDL_GetCurrentVideoDriver();
194 #else
195 const int maxNameLen = 20;
196 char sdlDriverName[maxNameLen];
197 sdlDriverName[0] = '\0';
198 SDL_VideoDriverName(sdlDriverName, maxNameLen);
199 #endif
200 debug(1, "Using SDL Video Driver \"%s\"", sdlDriverName);
201
202 // Create the default event source, in case a custom backend
203 // manager didn't provide one yet.
204 if (_eventSource == 0)
205 _eventSource = new SdlEventSource();
206
207 if (_eventManager == nullptr) {
208 DefaultEventManager *eventManager = new DefaultEventManager(_eventSource);
209 #if SDL_VERSION_ATLEAST(2, 0, 0)
210 // SDL 2 generates its own keyboard repeat events.
211 eventManager->setGenerateKeyRepeatEvents(false);
212 #endif
213 _eventManager = eventManager;
214 }
215
216
217 #ifdef USE_OPENGL
218 #if SDL_VERSION_ATLEAST(2, 0, 0)
219 SDL_DisplayMode displayMode;
220 if (!SDL_GetDesktopDisplayMode(0, &displayMode)) {
221 _desktopWidth = displayMode.w;
222 _desktopHeight = displayMode.h;
223 }
224 #else
225 // Query the desktop resolution. We simply hope nothing tried to change
226 // the resolution so far.
227 const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
228 if (videoInfo && videoInfo->current_w > 0 && videoInfo->current_h > 0) {
229 _desktopWidth = videoInfo->current_w;
230 _desktopHeight = videoInfo->current_h;
231 }
232 #endif
233 #endif
234
235 if (_graphicsManager == 0) {
236 #ifdef USE_OPENGL
237 // Setup a list with both SDL and OpenGL graphics modes. We only do
238 // this whenever the subclass did not already set up an graphics
239 // manager yet. This is because we don't know the type of the graphics
240 // manager of the subclass, thus we cannot easily switch between the
241 // OpenGL one and the set up one. It also is to be expected that the
242 // subclass does not want any switching of graphics managers anyway.
243 setupGraphicsModes();
244
245 if (ConfMan.hasKey("gfx_mode")) {
246 // If the gfx_mode is from OpenGL, create the OpenGL graphics manager
247 Common::String gfxMode(ConfMan.get("gfx_mode"));
248 for (uint i = _firstGLMode; i < _graphicsModeIds.size(); ++i) {
249 if (!scumm_stricmp(_graphicsModes[i].name, gfxMode.c_str())) {
250 _graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource, _window);
251 _graphicsMode = i;
252 break;
253 }
254 }
255 }
256 #endif
257
258 if (_graphicsManager == 0) {
259 _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window);
260 }
261 }
262
263 if (_savefileManager == 0)
264 _savefileManager = new DefaultSaveFileManager();
265
266 if (_mixerManager == 0) {
267 _mixerManager = new SdlMixerManager();
268 // Setup and start mixer
269 _mixerManager->init();
270 }
271
272 #ifdef ENABLE_EVENTRECORDER
273 g_eventRec.registerMixerManager(_mixerManager);
274
275 g_eventRec.registerTimerManager(new SdlTimerManager());
276 #else
277 if (_timerManager == 0)
278 _timerManager = new SdlTimerManager();
279 #endif
280
281 _audiocdManager = createAudioCDManager();
282
283 // Setup a custom program icon.
284 _window->setupIcon();
285
286 _inited = true;
287
288 ModularBackend::initBackend();
289
290 // We have to initialize the graphics manager before the event manager
291 // so the virtual keyboard can be initialized, but we have to add the
292 // graphics manager as an event observer after initializing the event
293 // manager.
294 dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->activateManager();
295 }
296
engineInit()297 void OSystem_SDL::engineInit() {
298 #if SDL_VERSION_ATLEAST(2, 0, 0)
299 dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->unlockWindowSize();
300 #endif
301 #ifdef USE_TASKBAR
302 // Add the started engine to the list of recent tasks
303 _taskbarManager->addRecent(ConfMan.getActiveDomainName(), ConfMan.get("description"));
304
305 // Set the overlay icon the current running engine
306 _taskbarManager->setOverlayIcon(ConfMan.getActiveDomainName(), ConfMan.get("description"));
307 #endif
308 }
309
engineDone()310 void OSystem_SDL::engineDone() {
311 #if SDL_VERSION_ATLEAST(2, 0, 0)
312 dynamic_cast<SdlGraphicsManager *>(_graphicsManager)->unlockWindowSize();
313 #endif
314 #ifdef USE_TASKBAR
315 // Remove overlay icon
316 _taskbarManager->setOverlayIcon("", "");
317 #endif
318 }
319
initSDL()320 void OSystem_SDL::initSDL() {
321 // Check if SDL has not been initialized
322 if (!_initedSDL) {
323 // We always initialize the video subsystem because we will need it to
324 // be initialized before the graphics managers to retrieve the desktop
325 // resolution, for example. WebOS also requires this initialization
326 // or otherwise the application won't start.
327 uint32 sdlFlags = SDL_INIT_VIDEO;
328
329 if (ConfMan.hasKey("disable_sdl_parachute"))
330 sdlFlags |= SDL_INIT_NOPARACHUTE;
331
332 // Initialize SDL (SDL Subsystems are initiliazed in the corresponding sdl managers)
333 if (SDL_Init(sdlFlags) == -1)
334 error("Could not initialize SDL: %s", SDL_GetError());
335
336 _initedSDL = true;
337 }
338
339 #ifdef USE_SDL_NET
340 // Check if SDL_net has not been initialized
341 if (!_initedSDLnet) {
342 // Initialize SDL_net
343 if (SDLNet_Init() == -1)
344 error("Could not initialize SDL_net: %s", SDLNet_GetError());
345
346 _initedSDLnet = true;
347 }
348 #endif
349 }
350
addSysArchivesToSearchSet(Common::SearchSet & s,int priority)351 void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
352
353 #ifdef DATA_PATH
354 // Add the global DATA_PATH to the directory search list
355 // FIXME: We use depth = 4 for now, to match the old code. May want to change that
356 Common::FSNode dataNode(DATA_PATH);
357 if (dataNode.exists() && dataNode.isDirectory()) {
358 s.add(DATA_PATH, new Common::FSDirectory(dataNode, 4), priority);
359 }
360 #endif
361
362 }
363
setWindowCaption(const char * caption)364 void OSystem_SDL::setWindowCaption(const char *caption) {
365 Common::String cap;
366 byte c;
367
368 // The string caption is supposed to be in LATIN-1 encoding.
369 // SDL expects UTF-8. So we perform the conversion here.
370 while ((c = *(const byte *)caption++)) {
371 if (c < 0x80)
372 cap += c;
373 else {
374 cap += 0xC0 | (c >> 6);
375 cap += 0x80 | (c & 0x3F);
376 }
377 }
378
379 _window->setWindowCaption(cap);
380 }
381
quit()382 void OSystem_SDL::quit() {
383 destroy();
384 exit(0);
385 }
386
fatalError()387 void OSystem_SDL::fatalError() {
388 destroy();
389 exit(1);
390 }
391
392
logMessage(LogMessageType::Type type,const char * message)393 void OSystem_SDL::logMessage(LogMessageType::Type type, const char *message) {
394 // First log to stdout/stderr
395 FILE *output = 0;
396
397 if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
398 output = stdout;
399 else
400 output = stderr;
401
402 fputs(message, output);
403 fflush(output);
404
405 // Then log into file (via the logger)
406 if (_logger)
407 _logger->print(message);
408 }
409
createLogFile()410 Common::WriteStream *OSystem_SDL::createLogFile() {
411 // Start out by resetting _logFilePath, so that in case
412 // of a failure, we know that no log file is open.
413 _logFilePath.clear();
414
415 Common::String logFile = getDefaultLogFileName();
416 if (logFile.empty())
417 return nullptr;
418
419 Common::FSNode file(logFile);
420 Common::WriteStream *stream = file.createWriteStream();
421 if (stream)
422 _logFilePath = logFile;
423 return stream;
424 }
425
getSystemLanguage() const426 Common::String OSystem_SDL::getSystemLanguage() const {
427 #if defined(USE_DETECTLANG) && !defined(WIN32)
428 // Activating current locale settings
429 const Common::String locale = setlocale(LC_ALL, "");
430
431 // Restore default C locale to prevent issues with
432 // portability of sscanf(), atof(), etc.
433 // See bug #3615148
434 setlocale(LC_ALL, "C");
435
436 // Detect the language from the locale
437 if (locale.empty()) {
438 return ModularBackend::getSystemLanguage();
439 } else {
440 int length = 0;
441
442 // Strip out additional information, like
443 // ".UTF-8" or the like. We do this, since
444 // our translation languages are usually
445 // specified without any charset information.
446 for (int size = locale.size(); length < size; ++length) {
447 // TODO: Check whether "@" should really be checked
448 // here.
449 if (locale[length] == '.' || locale[length] == ' ' || locale[length] == '@')
450 break;
451 }
452
453 return Common::String(locale.c_str(), length);
454 }
455 #else // USE_DETECTLANG
456 return ModularBackend::getSystemLanguage();
457 #endif // USE_DETECTLANG
458 }
459
460 #if SDL_VERSION_ATLEAST(2, 0, 0)
hasTextInClipboard()461 bool OSystem_SDL::hasTextInClipboard() {
462 return SDL_HasClipboardText() == SDL_TRUE;
463 }
464
getTextFromClipboard()465 Common::String OSystem_SDL::getTextFromClipboard() {
466 if (!hasTextInClipboard()) return "";
467
468 char *text = SDL_GetClipboardText();
469 // The string returned by SDL is in UTF-8. Convert to the
470 // current TranslationManager encoding or ISO-8859-1.
471 #ifdef USE_TRANSLATION
472 char *conv_text = SDL_iconv_string(TransMan.getCurrentCharset().c_str(), "UTF-8", text, SDL_strlen(text) + 1);
473 #else
474 char *conv_text = SDL_iconv_string("ISO-8859-1", "UTF-8", text, SDL_strlen(text) + 1);
475 #endif
476 if (conv_text) {
477 SDL_free(text);
478 text = conv_text;
479 }
480 Common::String strText = text;
481 SDL_free(text);
482
483 return strText;
484 }
485
setTextInClipboard(const Common::String & text)486 bool OSystem_SDL::setTextInClipboard(const Common::String &text) {
487 // The encoding we need to use is UTF-8. Assume we currently have the
488 // current TranslationManager encoding or ISO-8859-1.
489 #ifdef USE_TRANSLATION
490 char *utf8_text = SDL_iconv_string("UTF-8", TransMan.getCurrentCharset().c_str(), text.c_str(), text.size() + 1);
491 #else
492 char *utf8_text = SDL_iconv_string("UTF-8", "ISO-8859-1", text.c_str(), text.size() + 1);
493 #endif
494 if (utf8_text) {
495 int status = SDL_SetClipboardText(utf8_text);
496 SDL_free(utf8_text);
497 return status == 0;
498 }
499 return SDL_SetClipboardText(text.c_str()) == 0;
500 }
501 #endif
502
getMillis(bool skipRecord)503 uint32 OSystem_SDL::getMillis(bool skipRecord) {
504 uint32 millis = SDL_GetTicks();
505
506 #ifdef ENABLE_EVENTRECORDER
507 g_eventRec.processMillis(millis, skipRecord);
508 #endif
509
510 return millis;
511 }
512
delayMillis(uint msecs)513 void OSystem_SDL::delayMillis(uint msecs) {
514 #ifdef ENABLE_EVENTRECORDER
515 if (!g_eventRec.processDelayMillis())
516 #endif
517 SDL_Delay(msecs);
518 }
519
getTimeAndDate(TimeDate & td) const520 void OSystem_SDL::getTimeAndDate(TimeDate &td) const {
521 time_t curTime = time(0);
522 struct tm t = *localtime(&curTime);
523 td.tm_sec = t.tm_sec;
524 td.tm_min = t.tm_min;
525 td.tm_hour = t.tm_hour;
526 td.tm_mday = t.tm_mday;
527 td.tm_mon = t.tm_mon;
528 td.tm_year = t.tm_year;
529 td.tm_wday = t.tm_wday;
530 }
531
getMixer()532 Audio::Mixer *OSystem_SDL::getMixer() {
533 assert(_mixerManager);
534 return getMixerManager()->getMixer();
535 }
536
getMixerManager()537 SdlMixerManager *OSystem_SDL::getMixerManager() {
538 assert(_mixerManager);
539
540 #ifdef ENABLE_EVENTRECORDER
541 return g_eventRec.getMixerManager();
542 #else
543 return _mixerManager;
544 #endif
545 }
546
getTimerManager()547 Common::TimerManager *OSystem_SDL::getTimerManager() {
548 #ifdef ENABLE_EVENTRECORDER
549 return g_eventRec.getTimerManager();
550 #else
551 return _timerManager;
552 #endif
553 }
554
createAudioCDManager()555 AudioCDManager *OSystem_SDL::createAudioCDManager() {
556 // Audio CD support was removed with SDL 2.0
557 #if SDL_VERSION_ATLEAST(2, 0, 0)
558 return new DefaultAudioCDManager();
559 #else
560 return new SdlAudioCDManager();
561 #endif
562 }
563
getSavefileManager()564 Common::SaveFileManager *OSystem_SDL::getSavefileManager() {
565 #ifdef ENABLE_EVENTRECORDER
566 return g_eventRec.getSaveManager(_savefileManager);
567 #else
568 return _savefileManager;
569 #endif
570 }
571
572 //Not specified in base class
getScreenshotsPath()573 Common::String OSystem_SDL::getScreenshotsPath() {
574 Common::String path = ConfMan.get("screenshotpath");
575 if (!path.empty() && !path.hasSuffix("/"))
576 path += "/";
577 return path;
578 }
579
580 #ifdef USE_OPENGL
581
getSupportedGraphicsModes() const582 const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
583 if (_graphicsModes.empty()) {
584 return _graphicsManager->getSupportedGraphicsModes();
585 } else {
586 return _graphicsModes.begin();
587 }
588 }
589
getDefaultGraphicsMode() const590 int OSystem_SDL::getDefaultGraphicsMode() const {
591 if (_graphicsModes.empty()) {
592 return _graphicsManager->getDefaultGraphicsMode();
593 } else {
594 // Return the default graphics mode from the current graphics manager
595 if (_graphicsMode < _firstGLMode)
596 return _defaultSDLMode;
597 else
598 return _defaultGLMode;
599 }
600 }
601
setGraphicsMode(int mode)602 bool OSystem_SDL::setGraphicsMode(int mode) {
603 if (_graphicsModes.empty()) {
604 return _graphicsManager->setGraphicsMode(mode);
605 }
606
607 // Check whether a invalid mode is requested.
608 if (mode < 0 || (uint)mode >= _graphicsModeIds.size()) {
609 return false;
610 }
611
612 // Very hacky way to set up the old graphics manager state, in case we
613 // switch from SDL->OpenGL or OpenGL->SDL.
614 //
615 // This is a probably temporary workaround to fix bugs like #3368143
616 // "SDL/OpenGL: Crash when switching renderer backend".
617 SdlGraphicsManager *sdlGraphicsManager = dynamic_cast<SdlGraphicsManager *>(_graphicsManager);
618 SdlGraphicsManager::State state = sdlGraphicsManager->getState();
619
620 bool switchedManager = false;
621
622 // If the new mode and the current mode are not from the same graphics
623 // manager, delete and create the new mode graphics manager
624 if (_graphicsMode >= _firstGLMode && mode < _firstGLMode) {
625 debug(1, "switching to plain SDL graphics");
626 sdlGraphicsManager->deactivateManager();
627 delete _graphicsManager;
628 _graphicsManager = sdlGraphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window);
629
630 switchedManager = true;
631 } else if (_graphicsMode < _firstGLMode && mode >= _firstGLMode) {
632 debug(1, "switching to OpenGL graphics");
633 sdlGraphicsManager->deactivateManager();
634 delete _graphicsManager;
635 _graphicsManager = sdlGraphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource, _window);
636
637 switchedManager = true;
638 }
639
640 _graphicsMode = mode;
641
642 if (switchedManager) {
643 sdlGraphicsManager->activateManager();
644
645 // This failing will probably have bad consequences...
646 if (!sdlGraphicsManager->setState(state)) {
647 return false;
648 }
649
650 // Next setup the cursor again
651 CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
652 CursorMan.popCursor();
653
654 // Next setup cursor palette if needed
655 if (_graphicsManager->getFeatureState(kFeatureCursorPalette)) {
656 CursorMan.pushCursorPalette(0, 0, 0);
657 CursorMan.popCursorPalette();
658 }
659
660 _graphicsManager->beginGFXTransaction();
661 // Oh my god if this failed the client code might just explode.
662 return _graphicsManager->setGraphicsMode(_graphicsModeIds[mode]);
663 } else {
664 return _graphicsManager->setGraphicsMode(_graphicsModeIds[mode]);
665 }
666 }
667
getGraphicsMode() const668 int OSystem_SDL::getGraphicsMode() const {
669 if (_graphicsModes.empty()) {
670 return _graphicsManager->getGraphicsMode();
671 } else {
672 return _graphicsMode;
673 }
674 }
675
setupGraphicsModes()676 void OSystem_SDL::setupGraphicsModes() {
677 _graphicsModes.clear();
678 _graphicsModeIds.clear();
679 _defaultSDLMode = _defaultGLMode = -1;
680
681 // Count the number of graphics modes
682 const OSystem::GraphicsMode *srcMode;
683 int defaultMode;
684
685 GraphicsManager *manager = new SurfaceSdlGraphicsManager(_eventSource, _window);
686 srcMode = manager->getSupportedGraphicsModes();
687 defaultMode = manager->getDefaultGraphicsMode();
688 while (srcMode->name) {
689 if (defaultMode == srcMode->id) {
690 _defaultSDLMode = _graphicsModes.size();
691 }
692 _graphicsModes.push_back(*srcMode);
693 srcMode++;
694 }
695 delete manager;
696 assert(_defaultSDLMode != -1);
697
698 _firstGLMode = _graphicsModes.size();
699 manager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource, _window);
700 srcMode = manager->getSupportedGraphicsModes();
701 defaultMode = manager->getDefaultGraphicsMode();
702 while (srcMode->name) {
703 if (defaultMode == srcMode->id) {
704 _defaultGLMode = _graphicsModes.size();
705 }
706 _graphicsModes.push_back(*srcMode);
707 srcMode++;
708 }
709 delete manager;
710 manager = nullptr;
711 assert(_defaultGLMode != -1);
712
713 // Set a null mode at the end
714 GraphicsMode nullMode;
715 memset(&nullMode, 0, sizeof(nullMode));
716 _graphicsModes.push_back(nullMode);
717
718 // Set new internal ids for all modes
719 int i = 0;
720 OSystem::GraphicsMode *mode = _graphicsModes.begin();
721 while (mode->name) {
722 _graphicsModeIds.push_back(mode->id);
723 mode->id = i++;
724 mode++;
725 }
726 }
727 #endif
728
729 #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_SetColors(SDL_Surface * surface,SDL_Color * colors,int firstcolor,int ncolors)730 int SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) {
731 if (surface->format->palette) {
732 return !SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, ncolors) ? 1 : 0;
733 } else {
734 return 0;
735 }
736 }
737
SDL_SetAlpha(SDL_Surface * surface,Uint32 flag,Uint8 alpha)738 int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha) {
739 if (SDL_SetSurfaceAlphaMod(surface, alpha)) {
740 return -1;
741 }
742
743 if (alpha == 255 || !flag) {
744 if (SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE)) {
745 return -1;
746 }
747 } else {
748 if (SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND)) {
749 return -1;
750 }
751 }
752
753 return 0;
754 }
755
756 #undef SDL_SetColorKey
SDL_SetColorKey_replacement(SDL_Surface * surface,Uint32 flag,Uint32 key)757 int SDL_SetColorKey_replacement(SDL_Surface *surface, Uint32 flag, Uint32 key) {
758 return SDL_SetColorKey(surface, SDL_TRUE, key) ? -1 : 0;
759 }
760 #endif
761
convertEncoding(const char * to,const char * from,const char * string,size_t length)762 char *OSystem_SDL::convertEncoding(const char *to, const char *from, const char *string, size_t length) {
763 #if SDL_VERSION_ATLEAST(1, 2, 10)
764 int zeroBytes = 1;
765 if (Common::String(from).hasPrefixIgnoreCase("utf-16"))
766 zeroBytes = 2;
767 else if (Common::String(from).hasPrefixIgnoreCase("utf-32"))
768 zeroBytes = 4;
769
770 char *result;
771 // SDL_iconv_string() takes char * instead of const char * as it's third parameter
772 // with some older versions of SDL.
773 #if SDL_VERSION_ATLEAST(2, 0, 0)
774 result = SDL_iconv_string(to, from, string, length + zeroBytes);
775 #else
776 char *stringCopy = (char *) calloc(sizeof(char), length + zeroBytes);
777 memcpy(stringCopy, string, length);
778 result = SDL_iconv_string(to, from, stringCopy, length + zeroBytes);
779 free(stringCopy);
780 #endif // SDL_VERSION_ATLEAST(2, 0, 0)
781 if (result == nullptr)
782 return nullptr;
783
784 // We need to copy the result, so that we can use SDL_free()
785 // on the string returned by SDL_iconv_string() and free()
786 // can then be used on the copyed and returned string.
787 // Sometimes free() and SDL_free() aren't compatible and
788 // using free() instead of SDL_free() can cause crashes.
789 size_t newLength = Common::Encoding::stringLength(result, to);
790 zeroBytes = 1;
791 if (Common::String(to).hasPrefixIgnoreCase("utf-16"))
792 zeroBytes = 2;
793 else if (Common::String(to).hasPrefixIgnoreCase("utf-32"))
794 zeroBytes = 4;
795 char *finalResult = (char *) malloc(newLength + zeroBytes);
796 if (!finalResult) {
797 warning("Could not allocate memory for encoding conversion");
798 SDL_free(result);
799 return nullptr;
800 }
801 memcpy(finalResult, result, newLength + zeroBytes);
802 SDL_free(result);
803 return finalResult;
804 #else
805 return ModularBackend::convertEncoding(to, from, string, length);
806 #endif // SDL_VERSION_ATLEAST(1, 2, 10)
807 }
808
809