14 #include "../stdafx.h" 15 #include "../openttd.h" 16 #include "../gfx_func.h" 18 #include "../blitter/factory.hpp" 19 #include "../network/network.h" 20 #include "../thread.h" 21 #include "../progress.h" 22 #include "../core/random_func.hpp" 23 #include "../core/math_func.hpp" 24 #include "../fileio_func.h" 25 #include "../framerate_type.h" 29 #include <condition_variable> 32 #include "../safeguards.h" 36 static SDL_Surface *_sdl_screen;
37 static SDL_Surface *_sdl_realscreen;
38 static bool _all_modes;
50 #define MAX_DIRTY_RECTS 100 51 static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
52 static int _num_dirty_rects;
53 static int _use_hwpalette;
54 static int _requested_hwpalette;
58 if (_num_dirty_rects < MAX_DIRTY_RECTS) {
59 _dirty_rects[_num_dirty_rects].x = left;
60 _dirty_rects[_num_dirty_rects].y = top;
61 _dirty_rects[_num_dirty_rects].w = width;
62 _dirty_rects[_num_dirty_rects].h = height;
67 static void UpdatePalette(
bool init =
false)
71 for (
int i = 0; i != _local_palette.
count_dirty; i++) {
80 if (_sdl_screen != _sdl_realscreen && init) {
104 if (_sdl_screen != _sdl_realscreen && !init) {
115 SDL_BlitSurface(_sdl_screen,
nullptr, _sdl_realscreen,
nullptr);
116 SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0);
120 static void InitPalette()
128 static void CheckPaletteAnim()
152 static void DrawSurfaceToScreen()
156 int n = _num_dirty_rects;
159 _num_dirty_rects = 0;
160 if (n > MAX_DIRTY_RECTS) {
161 if (_sdl_screen != _sdl_realscreen) {
162 SDL_BlitSurface(_sdl_screen,
nullptr, _sdl_realscreen,
nullptr);
164 SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0);
166 if (_sdl_screen != _sdl_realscreen) {
167 for (
int i = 0; i < n; i++) {
168 SDL_BlitSurface(_sdl_screen, &_dirty_rects[i], _sdl_realscreen, &_dirty_rects[i]);
171 SDL_UpdateRects(_sdl_realscreen, n, _dirty_rects);
175 static void DrawSurfaceToScreenThread()
187 DrawSurfaceToScreen();
192 static const Dimension _default_resolutions[] = {
206 static void GetVideoModes()
208 SDL_Rect **modes = SDL_ListModes(
nullptr, SDL_SWSURFACE | SDL_FULLSCREEN);
209 if (modes ==
nullptr)
usererror(
"sdl: no modes available");
213 _all_modes = (SDL_ListModes(
nullptr, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (
void*)-1);
214 if (modes == (
void*)-1) {
215 for (uint i = 0; i <
lengthof(_default_resolutions); i++) {
216 if (SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) {
221 for (
int i = 0; modes[i]; i++) {
222 uint w = modes[i]->w;
223 uint h = modes[i]->h;
224 if (w < 640 || h < 480)
continue;
233 static void GetAvailableVideoMode(uint *w, uint *h)
246 if (newdelta < delta) {
255 bool VideoDriver_SDL::CreateMainSurface(uint w, uint h)
257 SDL_Surface *newscreen, *icon;
262 GetAvailableVideoMode(&w, &h);
264 DEBUG(driver, 1,
"SDL: using mode %ux%ux%d", w, h, bpp);
266 if (bpp == 0)
usererror(
"Can't use a blitter that blits 0 bpp for normal visuals");
268 char icon_path[MAX_PATH];
271 icon = SDL_LoadBMP(icon_path);
272 if (icon !=
nullptr) {
274 uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255);
276 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap);
277 SDL_WM_SetIcon(icon,
nullptr);
278 SDL_FreeSurface(icon);
282 if (_use_hwpalette == 2) {
304 want_hwpalette = bpp == 8 && _fullscreen && _support8bpp ==
S8BPP_HARDWARE;
307 want_hwpalette = _use_hwpalette;
310 if (want_hwpalette)
DEBUG(driver, 1,
"SDL: requesting hardware palette");
313 if (_sdl_screen !=
nullptr && _sdl_screen != _sdl_realscreen) SDL_FreeSurface(_sdl_screen);
315 if (_sdl_realscreen !=
nullptr) {
316 if (_requested_hwpalette != want_hwpalette) {
325 DEBUG(driver, 0,
"SDL: Restarting SDL video subsystem, to force hwpalette change");
326 SDL_QuitSubSystem(SDL_INIT_VIDEO);
327 SDL_InitSubSystem(SDL_INIT_VIDEO);
336 _requested_hwpalette = want_hwpalette;
339 newscreen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE));
340 if (newscreen ==
nullptr) {
341 DEBUG(driver, 0,
"SDL: Couldn't allocate a window to draw on");
344 _sdl_realscreen = newscreen;
346 if (bpp == 8 && (_sdl_realscreen->flags & SDL_HWPALETTE) != SDL_HWPALETTE) {
365 DEBUG(driver, 1,
"SDL: using shadow surface");
366 newscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0);
367 if (newscreen ==
nullptr) {
368 DEBUG(driver, 0,
"SDL: Couldn't allocate a shadow surface to draw on");
374 _num_dirty_rects = 0;
376 _screen.width = newscreen->w;
377 _screen.height = newscreen->h;
378 _screen.pitch = newscreen->pitch / (bpp / 8);
379 _screen.dst_ptr = newscreen->pixels;
380 _sdl_screen = newscreen;
385 if (_fullscreen) _cursor.
in_window =
true;
392 seprintf(caption,
lastof(caption),
"OpenTTD %s", _openttd_revision);
393 SDL_WM_SetCaption(caption, caption);
400 bool VideoDriver_SDL::ClaimMousePointer()
407 #if SDL_VERSION_ATLEAST(1, 3, 0) 416 #define AS(x, z) {x, 0, z} 417 #define AM(x, y, z, w) {x, (byte)(y - x), z} 421 AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),
423 AS(SDLK_DOWN, WKC_DOWN),
424 AS(SDLK_LEFT, WKC_LEFT),
425 AS(SDLK_RIGHT, WKC_RIGHT),
427 AS(SDLK_HOME, WKC_HOME),
428 AS(SDLK_END, WKC_END),
430 AS(SDLK_INSERT, WKC_INSERT),
431 AS(SDLK_DELETE, WKC_DELETE),
434 AM(SDLK_a, SDLK_z,
'A',
'Z'),
435 AM(SDLK_0, SDLK_9,
'0',
'9'),
437 AS(SDLK_ESCAPE, WKC_ESC),
438 AS(SDLK_PAUSE, WKC_PAUSE),
439 AS(SDLK_BACKSPACE, WKC_BACKSPACE),
441 AS(SDLK_SPACE, WKC_SPACE),
442 AS(SDLK_RETURN, WKC_RETURN),
443 AS(SDLK_TAB, WKC_TAB),
446 AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12),
449 AM(SDLK_KP0, SDLK_KP9,
'0',
'9'),
450 AS(SDLK_KP_DIVIDE, WKC_NUM_DIV),
451 AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL),
452 AS(SDLK_KP_MINUS, WKC_NUM_MINUS),
453 AS(SDLK_KP_PLUS, WKC_NUM_PLUS),
454 AS(SDLK_KP_ENTER, WKC_NUM_ENTER),
455 AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL),
471 static uint ConvertSdlKeyIntoMy(SDL_keysym *sym,
WChar *character)
476 for (map = _vk_mapping; map !=
endof(_vk_mapping); ++map) {
477 if ((uint)(sym->sym - map->vk_from) <= map->vk_count) {
478 key = sym->sym - map->vk_from + map->map_to;
484 #if defined(_WIN32) || defined(__OS2__) 485 if (sym->scancode == 41) key = WKC_BACKQUOTE;
486 #elif defined(__APPLE__) 487 if (sym->scancode == 10) key = WKC_BACKQUOTE;
488 #elif defined(__SVR4) && defined(__sun) 489 if (sym->scancode == 60) key = WKC_BACKQUOTE;
490 if (sym->scancode == 49) key = WKC_BACKSPACE;
491 #elif defined(__sgi__) 492 if (sym->scancode == 22) key = WKC_BACKQUOTE;
494 if (sym->scancode == 49) key = WKC_BACKQUOTE;
498 if (sym->mod & KMOD_META) key |= WKC_META;
499 if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT;
500 if (sym->mod & KMOD_CTRL) key |= WKC_CTRL;
501 if (sym->mod & KMOD_ALT) key |= WKC_ALT;
503 *character = sym->unicode;
507 int VideoDriver_SDL::PollEvent()
511 if (!SDL_PollEvent(&ev))
return -2;
514 case SDL_MOUSEMOTION:
516 SDL_WarpMouse(_cursor.
pos.x, _cursor.
pos.y);
521 case SDL_MOUSEBUTTONDOWN:
523 ev.button.button = SDL_BUTTON_RIGHT;
526 switch (ev.button.button) {
527 case SDL_BUTTON_LEFT:
531 case SDL_BUTTON_RIGHT:
536 case SDL_BUTTON_WHEELUP: _cursor.
wheel--;
break;
537 case SDL_BUTTON_WHEELDOWN: _cursor.
wheel++;
break;
544 case SDL_MOUSEBUTTONUP:
549 }
else if (ev.button.button == SDL_BUTTON_LEFT) {
552 }
else if (ev.button.button == SDL_BUTTON_RIGHT) {
558 case SDL_ACTIVEEVENT:
559 if (!(ev.active.state & SDL_APPMOUSEFOCUS))
break;
561 if (ev.active.gain) {
570 HandleExitGameRequest();
574 if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) &&
575 (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
576 ToggleFullScreen(!_fullscreen);
579 uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character);
584 case SDL_VIDEORESIZE: {
585 int w =
max(ev.resize.w, 64);
586 int h =
max(ev.resize.h, 64);
587 CreateMainSurface(w, h);
590 case SDL_VIDEOEXPOSE: {
594 _num_dirty_rects = MAX_DIRTY_RECTS + 1;
610 if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
611 ret_code = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
612 }
else if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
613 ret_code = SDL_InitSubSystem(SDL_INIT_VIDEO);
615 if (ret_code == -1)
return SDL_GetError();
619 return SDL_GetError();
622 SDL_VideoDriverName(buf,
sizeof buf);
623 DEBUG(driver, 1,
"SDL: using driver '%s'", buf);
633 void VideoDriver_SDL::SetupKeyboard()
635 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
636 SDL_EnableUNICODE(1);
641 SDL_QuitSubSystem(SDL_INIT_VIDEO);
642 if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
649 uint32 cur_ticks = SDL_GetTicks();
650 uint32 last_cur_ticks = cur_ticks;
658 std::thread draw_thread;
659 std::unique_lock<std::recursive_mutex> draw_lock;
667 draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
679 _draw_mutex =
nullptr;
691 uint32 prev_cur_ticks = cur_ticks;
694 while (PollEvent() == -1) {}
695 if (_exit_game)
break;
697 mod = SDL_GetModState();
698 #if SDL_VERSION_ATLEAST(1, 3, 0) 699 keys = SDL_GetKeyboardState(&numkeys);
701 keys = SDL_GetKeyState(&numkeys);
708 #if SDL_VERSION_ATLEAST(1, 3, 0) 709 if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0)
711 if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0)
715 if (!
_networking && _game_mode != GM_MENU) _fast_forward |= 2;
716 }
else if (_fast_forward & 2) {
720 cur_ticks = SDL_GetTicks();
721 if (cur_ticks >= next_tick || (_fast_forward && !
_pause_mode) || cur_ticks < prev_cur_ticks) {
723 last_cur_ticks = cur_ticks;
733 #if SDL_VERSION_ATLEAST(1, 3, 0) 734 (keys[SDL_SCANCODE_LEFT] ? 1 : 0) |
735 (keys[SDL_SCANCODE_UP] ? 2 : 0) |
736 (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) |
737 (keys[SDL_SCANCODE_DOWN] ? 8 : 0);
739 (keys[SDLK_LEFT] ? 1 : 0) |
740 (keys[SDLK_UP] ? 2 : 0) |
741 (keys[SDLK_RIGHT] ? 4 : 0) |
742 (keys[SDLK_DOWN] ? 8 : 0);
772 DrawSurfaceToScreen();
781 if (draw_lock.owns_lock()) draw_lock.unlock();
795 std::unique_lock<std::recursive_mutex>
lock;
796 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
798 return CreateMainSurface(w, h);
803 std::unique_lock<std::recursive_mutex>
lock;
804 if (
_draw_mutex !=
nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
806 _fullscreen = fullscreen;
820 return CreateMainSurface(_screen.width, _screen.height);
const char * GetDriverParam(const char *const *parm, const char *name)
Get a string parameter the list of parameters.
bool _networking
are we in networking mode?
uint32 _realtime_tick
The real time in the game.
Point pos
logical mouse position
Information about the currently used palette.
void AcquireBlitterLock() override
Acquire any lock(s) required to be held when changing blitters.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
bool _right_button_down
Is right mouse button pressed?
void MakeDirty(int left, int top, int width, int height) override
Mark a particular area dirty.
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
Base of the SDL video driver.
void Stop() override
Stop this driver.
void CSleep(int milliseconds)
Sleep on the current thread for a defined time.
Dimension _cur_resolution
The current resolution.
static volatile bool _draw_continue
Should we keep continue drawing?
#define lastof(x)
Get the last element of an fixed size array.
How all blitters should look like.
Subdirectory for all base data (base sets, intro game)
static T max(const T a, const T b)
Returns the maximum of two values.
virtual void PostResize()
Post resize event.
Palette animation should be done by video backend (8bpp only!)
bool _left_button_clicked
Is left mouse button clicked?
std::vector< Dimension > _resolutions
List of resolutions.
bool AfterBlitterChange() override
Callback invoked after the blitter was changed.
static std::condition_variable_any * _draw_signal
Signal to draw the next frame.
bool _ctrl_pressed
Is Ctrl pressed?
bool StartNewThread(std::thread *thr, const char *name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
bool _right_button_clicked
Is right mouse button clicked?
The blitter takes care of the palette animation.
char * FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename)
Find a path to the filename in one of the search directories.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
bool _left_button_down
Is left mouse button pressed?
std::mutex lock
synchronization for playback status fields
void CDECL usererror(const char *s,...)
Error handling for fatal user errors.
int wheel
mouse wheel movement
bool UpdateCursorPosition(int x, int y, bool queued_warp)
Update cursor position on mouse movement.
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
void HandleKeypress(uint keycode, WChar key)
Handle keyboard input.
byte _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
void HandleMouseEvents()
Handle a mouse event from the video driver.
#define lengthof(x)
Return the length of an fixed size array.
bool ToggleFullscreen(bool fullscreen) override
Change the full screen setting.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
int first_dirty
The first dirty element.
PauseMode _pause_mode
The current pause mode.
Palette _cur_palette
Current palette.
bool _shift_pressed
Is Shift pressed?
#define DEBUG(name, level,...)
Output a line of debugging information.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
static bool _draw_threaded
Whether the drawing is/may be done in a separate thread.
void HandleCtrlChanged()
State of CONTROL key has changed.
void MainLoop() override
Perform the actual drawing.
Speed of painting drawn video buffer.
void NetworkDrawChatMessage()
Draw the chat message-box.
static Palette _local_palette
Local copy of the palette for use in the drawing thread.
#define endof(x)
Get the end element of an fixed size array.
bool in_window
mouse inside this window, determines drawing logic
bool ChangeResolution(int w, int h) override
Change the resolution of the window.
virtual uint8 GetScreenDepth()=0
Get the screen depth this blitter works for.
#define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview)
AirportSpec definition for airports with at least one depot.
void ReleaseBlitterLock() override
Release any lock(s) required to be held when changing blitters.
int GetDriverParamInt(const char *const *parm, const char *name, int def)
Get an integer parameter the list of parameters.
static std::recursive_mutex * _draw_mutex
Mutex to keep the access to the shared memory controlled.
bool _rightclick_emulate
Whether right clicking is emulated.
void GameSizeChanged()
Size of the application screen changed.
Factory for the SDL video driver.
int count_dirty
The number of dirty elements.
static T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
uint32 WChar
Type for wide characters, i.e.
Dimensions (a width and height) of a rectangle in 2D.
Full 8bpp support by OS and hardware.
static bool HasModalProgress()
Check if we are currently in a modal progress state.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
const char * Start(const char *const *param) override
Start this driver.
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.