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/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 "../safeguards.h" 33 static SDL_Surface *_sdl_screen;
34 static SDL_Surface *_sdl_realscreen;
35 static bool _all_modes;
47 #define MAX_DIRTY_RECTS 100 48 static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
49 static int _num_dirty_rects;
50 static int _use_hwpalette;
51 static int _requested_hwpalette;
55 if (_num_dirty_rects < MAX_DIRTY_RECTS) {
56 _dirty_rects[_num_dirty_rects].x = left;
57 _dirty_rects[_num_dirty_rects].y = top;
58 _dirty_rects[_num_dirty_rects].w = width;
59 _dirty_rects[_num_dirty_rects].h = height;
64 static void UpdatePalette(
bool init =
false)
68 for (
int i = 0; i != _local_palette.
count_dirty; i++) {
77 if (_sdl_screen != _sdl_realscreen && init) {
101 if (_sdl_screen != _sdl_realscreen && !init) {
112 SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL);
113 SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0);
117 static void InitPalette()
125 static void CheckPaletteAnim()
149 static void DrawSurfaceToScreen()
153 int n = _num_dirty_rects;
156 _num_dirty_rects = 0;
157 if (n > MAX_DIRTY_RECTS) {
158 if (_sdl_screen != _sdl_realscreen) {
159 SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL);
161 SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0);
163 if (_sdl_screen != _sdl_realscreen) {
164 for (
int i = 0; i < n; i++) {
165 SDL_BlitSurface(_sdl_screen, &_dirty_rects[i], _sdl_realscreen, &_dirty_rects[i]);
168 SDL_UpdateRects(_sdl_realscreen, n, _dirty_rects);
172 static void DrawSurfaceToScreenThread(
void *)
184 DrawSurfaceToScreen();
189 _draw_thread->
Exit();
192 static const Dimension _default_resolutions[] = {
206 static void GetVideoModes()
208 SDL_Rect **modes = SDL_ListModes(NULL, SDL_SWSURFACE | SDL_FULLSCREEN);
209 if (modes == NULL)
usererror(
"sdl: no modes available");
211 _all_modes = (SDL_ListModes(NULL, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (
void*)-1);
212 if (modes == (
void*)-1) {
214 for (uint i = 0; i <
lengthof(_default_resolutions); i++) {
215 if (SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) {
223 for (
int i = 0; modes[i]; i++) {
224 uint w = modes[i]->w;
225 uint h = modes[i]->h;
227 for (j = 0; j < n; j++) {
242 static void GetAvailableVideoMode(uint *w, uint *h)
257 if (newdelta < delta) {
266 bool VideoDriver_SDL::CreateMainSurface(uint w, uint h)
268 SDL_Surface *newscreen, *icon;
273 GetAvailableVideoMode(&w, &h);
275 DEBUG(driver, 1,
"SDL: using mode %ux%ux%d", w, h, bpp);
277 if (bpp == 0)
usererror(
"Can't use a blitter that blits 0 bpp for normal visuals");
279 char icon_path[MAX_PATH];
282 icon = SDL_LoadBMP(icon_path);
285 uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255);
287 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap);
288 SDL_WM_SetIcon(icon, NULL);
289 SDL_FreeSurface(icon);
293 if (_use_hwpalette == 2) {
315 want_hwpalette = bpp == 8 && _fullscreen && _support8bpp ==
S8BPP_HARDWARE;
318 want_hwpalette = _use_hwpalette;
321 if (want_hwpalette)
DEBUG(driver, 1,
"SDL: requesting hardware palette");
324 if (_sdl_screen != NULL && _sdl_screen != _sdl_realscreen) SDL_FreeSurface(_sdl_screen);
326 if (_sdl_realscreen != NULL) {
327 if (_requested_hwpalette != want_hwpalette) {
336 DEBUG(driver, 0,
"SDL: Restarting SDL video subsystem, to force hwpalette change");
337 SDL_QuitSubSystem(SDL_INIT_VIDEO);
338 SDL_InitSubSystem(SDL_INIT_VIDEO);
347 _requested_hwpalette = want_hwpalette;
350 newscreen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE));
351 if (newscreen == NULL) {
352 DEBUG(driver, 0,
"SDL: Couldn't allocate a window to draw on");
355 _sdl_realscreen = newscreen;
357 if (bpp == 8 && (_sdl_realscreen->flags & SDL_HWPALETTE) != SDL_HWPALETTE) {
376 DEBUG(driver, 1,
"SDL: using shadow surface");
377 newscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0);
378 if (newscreen == NULL) {
379 DEBUG(driver, 0,
"SDL: Couldn't allocate a shadow surface to draw on");
385 _num_dirty_rects = 0;
387 _screen.width = newscreen->w;
388 _screen.height = newscreen->h;
389 _screen.pitch = newscreen->pitch / (bpp / 8);
390 _screen.dst_ptr = newscreen->pixels;
391 _sdl_screen = newscreen;
396 if (_fullscreen) _cursor.
in_window =
true;
403 seprintf(caption,
lastof(caption),
"OpenTTD %s", _openttd_revision);
404 SDL_WM_SetCaption(caption, caption);
411 bool VideoDriver_SDL::ClaimMousePointer()
418 #if SDL_VERSION_ATLEAST(1, 3, 0) 427 #define AS(x, z) {x, 0, z} 428 #define AM(x, y, z, w) {x, (byte)(y - x), z} 432 AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN),
434 AS(SDLK_DOWN, WKC_DOWN),
435 AS(SDLK_LEFT, WKC_LEFT),
436 AS(SDLK_RIGHT, WKC_RIGHT),
438 AS(SDLK_HOME, WKC_HOME),
439 AS(SDLK_END, WKC_END),
441 AS(SDLK_INSERT, WKC_INSERT),
442 AS(SDLK_DELETE, WKC_DELETE),
445 AM(SDLK_a, SDLK_z,
'A',
'Z'),
446 AM(SDLK_0, SDLK_9,
'0',
'9'),
448 AS(SDLK_ESCAPE, WKC_ESC),
449 AS(SDLK_PAUSE, WKC_PAUSE),
450 AS(SDLK_BACKSPACE, WKC_BACKSPACE),
452 AS(SDLK_SPACE, WKC_SPACE),
453 AS(SDLK_RETURN, WKC_RETURN),
454 AS(SDLK_TAB, WKC_TAB),
457 AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12),
460 AM(SDLK_KP0, SDLK_KP9,
'0',
'9'),
461 AS(SDLK_KP_DIVIDE, WKC_NUM_DIV),
462 AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL),
463 AS(SDLK_KP_MINUS, WKC_NUM_MINUS),
464 AS(SDLK_KP_PLUS, WKC_NUM_PLUS),
465 AS(SDLK_KP_ENTER, WKC_NUM_ENTER),
466 AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL),
482 static uint ConvertSdlKeyIntoMy(SDL_keysym *sym,
WChar *character)
487 for (map = _vk_mapping; map !=
endof(_vk_mapping); ++map) {
488 if ((uint)(sym->sym - map->vk_from) <= map->vk_count) {
489 key = sym->sym - map->vk_from + map->map_to;
495 #if defined(_WIN32) || defined(__OS2__) 496 if (sym->scancode == 41) key = WKC_BACKQUOTE;
497 #elif defined(__APPLE__) 498 if (sym->scancode == 10) key = WKC_BACKQUOTE;
499 #elif defined(__MORPHOS__) 500 if (sym->scancode == 0) key = WKC_BACKQUOTE;
501 #elif defined(__BEOS__) 502 if (sym->scancode == 17) key = WKC_BACKQUOTE;
503 #elif defined(__SVR4) && defined(__sun) 504 if (sym->scancode == 60) key = WKC_BACKQUOTE;
505 if (sym->scancode == 49) key = WKC_BACKSPACE;
506 #elif defined(__sgi__) 507 if (sym->scancode == 22) key = WKC_BACKQUOTE;
509 if (sym->scancode == 49) key = WKC_BACKQUOTE;
513 if (sym->mod & KMOD_META) key |= WKC_META;
514 if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT;
515 if (sym->mod & KMOD_CTRL) key |= WKC_CTRL;
516 if (sym->mod & KMOD_ALT) key |= WKC_ALT;
518 *character = sym->unicode;
522 int VideoDriver_SDL::PollEvent()
526 if (!SDL_PollEvent(&ev))
return -2;
529 case SDL_MOUSEMOTION:
531 SDL_WarpMouse(_cursor.
pos.x, _cursor.
pos.y);
536 case SDL_MOUSEBUTTONDOWN:
538 ev.button.button = SDL_BUTTON_RIGHT;
541 switch (ev.button.button) {
542 case SDL_BUTTON_LEFT:
546 case SDL_BUTTON_RIGHT:
551 case SDL_BUTTON_WHEELUP: _cursor.
wheel--;
break;
552 case SDL_BUTTON_WHEELDOWN: _cursor.
wheel++;
break;
559 case SDL_MOUSEBUTTONUP:
564 }
else if (ev.button.button == SDL_BUTTON_LEFT) {
567 }
else if (ev.button.button == SDL_BUTTON_RIGHT) {
573 case SDL_ACTIVEEVENT:
574 if (!(ev.active.state & SDL_APPMOUSEFOCUS))
break;
576 if (ev.active.gain) {
585 HandleExitGameRequest();
589 if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) &&
590 (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) {
591 ToggleFullScreen(!_fullscreen);
594 uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character);
599 case SDL_VIDEORESIZE: {
600 int w =
max(ev.resize.w, 64);
601 int h =
max(ev.resize.h, 64);
602 CreateMainSurface(w, h);
605 case SDL_VIDEOEXPOSE: {
609 _num_dirty_rects = MAX_DIRTY_RECTS + 1;
625 if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
626 ret_code = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
627 }
else if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
628 ret_code = SDL_InitSubSystem(SDL_INIT_VIDEO);
630 if (ret_code == -1)
return SDL_GetError();
634 return SDL_GetError();
637 SDL_VideoDriverName(buf,
sizeof buf);
638 DEBUG(driver, 1,
"SDL: using driver '%s'", buf);
648 void VideoDriver_SDL::SetupKeyboard()
650 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
651 SDL_EnableUNICODE(1);
656 SDL_QuitSubSystem(SDL_INIT_VIDEO);
657 if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
664 uint32 cur_ticks = SDL_GetTicks();
665 uint32 last_cur_ticks = cur_ticks;
677 if (_draw_mutex == NULL) {
700 uint32 prev_cur_ticks = cur_ticks;
703 while (PollEvent() == -1) {}
704 if (_exit_game)
break;
706 mod = SDL_GetModState();
707 #if SDL_VERSION_ATLEAST(1, 3, 0) 708 keys = SDL_GetKeyboardState(&numkeys);
710 keys = SDL_GetKeyState(&numkeys);
717 #if SDL_VERSION_ATLEAST(1, 3, 0) 718 if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0)
720 if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0)
724 if (!
_networking && _game_mode != GM_MENU) _fast_forward |= 2;
725 }
else if (_fast_forward & 2) {
729 cur_ticks = SDL_GetTicks();
730 if (cur_ticks >= next_tick || (_fast_forward && !
_pause_mode) || cur_ticks < prev_cur_ticks) {
732 last_cur_ticks = cur_ticks;
742 #if SDL_VERSION_ATLEAST(1, 3, 0) 743 (keys[SDL_SCANCODE_LEFT] ? 1 : 0) |
744 (keys[SDL_SCANCODE_UP] ? 2 : 0) |
745 (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) |
746 (keys[SDL_SCANCODE_DOWN] ? 8 : 0);
748 (keys[SDLK_LEFT] ? 1 : 0) |
749 (keys[SDLK_UP] ? 2 : 0) |
750 (keys[SDLK_RIGHT] ? 4 : 0) |
751 (keys[SDLK_DOWN] ? 8 : 0);
757 if (_draw_mutex != NULL) _draw_mutex->
EndCritical();
767 if (_draw_mutex != NULL) _draw_mutex->
EndCritical();
781 DrawSurfaceToScreen();
785 if (_draw_mutex != NULL) {
791 _draw_thread->
Join();
804 bool ret = CreateMainSurface(w, h);
805 if (_draw_mutex != NULL) _draw_mutex->
EndCritical(
true);
812 _fullscreen = fullscreen;
821 if (_draw_mutex != NULL) _draw_mutex->
EndCritical(
true);
827 return CreateMainSurface(_screen.width, _screen.height);
837 if (_draw_mutex != NULL) _draw_mutex->
EndCritical(
true);
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.
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?
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
const char * Start(const char *const *param)
Start this driver.
void MainLoop()
Perform the actual drawing.
bool ChangeResolution(int w, int h)
Change the resolution of the window.
Base of the SDL video driver.
Dimension _cur_resolution
The current resolution.
static volatile bool _draw_continue
Should we keep continue drawing?
int _num_resolutions
The number of resolutions.
#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 EndCritical(bool allow_recursive=false)=0
End of the critical section.
virtual void PostResize()
Post resize event.
Palette animation should be done by video backend (8bpp only!)
virtual void SendSignal()=0
Send a signal and wake the 'thread' that was waiting for it.
bool _left_button_clicked
Is left mouse button clicked?
bool _ctrl_pressed
Is Ctrl pressed?
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?
bool ToggleFullscreen(bool fullscreen)
Change the full screen setting.
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.
static ThreadMutex * New()
Create a new mutex.
void HandleKeypress(uint keycode, WChar key)
Handle keyboard input.
byte _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
static ThreadObject * _draw_thread
Thread used to 'draw' to the screen, i.e.
void HandleMouseEvents()
Handle a mouse event from the video driver.
#define lengthof(x)
Return the length of an fixed size array.
PauseModeByte _pause_mode
The current pause mode.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
int first_dirty
The first dirty element.
Palette _cur_palette
Current palette.
bool _shift_pressed
Is Shift pressed?
#define DEBUG(name, level,...)
Output a line of debugging information.
static ThreadMutex * _draw_mutex
Mutex to keep the access to the shared memory controlled.
Dimension _resolutions[32]
List of resolutions.
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.
virtual void Join()=0
Join this thread.
void Stop()
Stop this driver.
Speed of painting drawn video buffer.
void ReleaseBlitterLock()
Release any lock(s) required to be held when changing blitters.
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 AfterBlitterChange()
Callback invoked after the blitter was changed.
virtual void WaitForSignal()=0
Wait for a signal to be send.
void AcquireBlitterLock()
Acquire any lock(s) required to be held when changing blitters.
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.
int GetDriverParamInt(const char *const *parm, const char *name, int def)
Get an integer parameter the list of parameters.
bool _rightclick_emulate
Whether right clicking is emulated.
void GameSizeChanged()
Size of the application screen changed.
virtual void BeginCritical(bool allow_recursive=false)=0
Begin the critical section.
void MakeDirty(int left, int top, int width, int height)
Mark a particular area dirty.
virtual bool Exit()=0
Exit this thread.
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.
A Thread Object which works on all our supported OSes.
static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread=NULL, const char *name=NULL)
Create a thread; proc will be called as first function inside the thread, with optional params...
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.
void UpdateWindows()
Update the continuously changing contents of the windows, such as the viewports.