1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct OptionInfo options;
33 struct VideoSystemInfo video;
34 struct AudioSystemInfo audio;
36 struct TileCursorInfo tile_cursor;
37 struct OverlayInfo overlay;
38 struct ArtworkInfo artwork;
39 struct JoystickInfo joystick;
40 struct SetupInfo setup;
42 LevelDirTree *leveldir_first_all = NULL;
43 LevelDirTree *leveldir_first = NULL;
44 LevelDirTree *leveldir_current = NULL;
47 struct LevelStats level_stats[MAX_LEVELS];
49 DrawWindow *window = NULL;
50 DrawBuffer *backbuffer = NULL;
51 DrawBuffer *drawto = NULL;
53 int button_status = MB_NOT_PRESSED;
54 boolean motion_status = FALSE;
55 int wheel_steps = DEFAULT_WHEEL_STEPS;
56 #if defined(TARGET_SDL2)
57 boolean keyrepeat_status = TRUE;
60 int redraw_mask = REDRAW_NONE;
65 /* ========================================================================= */
66 /* init/close functions */
67 /* ========================================================================= */
69 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
70 char *program_title, char *icon_title,
71 char *icon_filename, char *cookie_prefix,
72 char *program_version_string, int program_version)
74 program.command_basepath = getBasePath(argv0);
75 program.command_basename = getBaseName(argv0);
77 program.config_filename = config_filename;
79 program.userdata_subdir = userdata_subdir;
80 program.userdata_path = getUserGameDataDir();
82 program.program_title = program_title;
83 program.window_title = "(undefined)";
84 program.icon_title = icon_title;
86 program.icon_filename = icon_filename;
88 program.cookie_prefix = cookie_prefix;
90 program.version_super = VERSION_SUPER(program_version);
91 program.version_major = VERSION_MAJOR(program_version);
92 program.version_minor = VERSION_MINOR(program_version);
93 program.version_patch = VERSION_PATCH(program_version);
94 program.version_ident = program_version;
96 program.version_string = program_version_string;
98 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
99 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
100 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
101 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
103 program.headless = FALSE;
106 void InitScoresInfo()
108 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
110 program.global_scores = directoryExists(global_scores_dir);
111 program.many_scores_per_name = !program.global_scores;
115 if (program.global_scores)
117 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
119 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
120 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
124 Error(ERR_DEBUG, "Using private, single-user scores directory.");
128 free(global_scores_dir);
131 void SetWindowTitle()
133 program.window_title = program.window_title_function();
138 void InitWindowTitleFunction(char *(*window_title_function)(void))
140 program.window_title_function = window_title_function;
143 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
145 program.exit_message_function = exit_message_function;
148 void InitExitFunction(void (*exit_function)(int))
150 program.exit_function = exit_function;
152 /* set signal handlers to custom exit function */
153 // signal(SIGINT, exit_function);
154 signal(SIGTERM, exit_function);
156 /* set exit function to automatically cleanup SDL stuff after exit() */
160 void InitPlatformDependentStuff(void)
162 // this is initialized in GetOptions(), but may already be used before
163 options.verbose = TRUE;
167 #if defined(TARGET_SDL2)
168 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
170 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
173 if (SDL_Init(sdl_init_flags) < 0)
174 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
179 void ClosePlatformDependentStuff(void)
184 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
185 int real_sx, int real_sy,
186 int full_sxsize, int full_sysize,
187 Bitmap *field_save_buffer)
193 gfx.real_sx = real_sx;
194 gfx.real_sy = real_sy;
195 gfx.full_sxsize = full_sxsize;
196 gfx.full_sysize = full_sysize;
198 gfx.field_save_buffer = field_save_buffer;
200 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
201 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
204 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
206 gfx.game_tile_size = game_tile_size;
207 gfx.standard_tile_size = standard_tile_size;
210 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
218 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
226 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
234 void InitGfxWindowInfo(int win_xsize, int win_ysize)
236 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
238 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
240 #if defined(TARGET_SDL2)
241 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
249 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
252 gfx.win_xsize = win_xsize;
253 gfx.win_ysize = win_ysize;
255 gfx.background_bitmap_mask = REDRAW_NONE;
258 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
260 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
261 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
262 gfx.scrollbuffer_width = scrollbuffer_width;
263 gfx.scrollbuffer_height = scrollbuffer_height;
266 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
268 gfx.clipping_enabled = enabled;
271 gfx.clip_width = width;
272 gfx.clip_height = height;
275 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
277 gfx.draw_busy_anim_function = draw_busy_anim_function;
280 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
282 gfx.draw_global_anim_function = draw_global_anim_function;
285 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
287 gfx.draw_global_border_function = draw_global_border_function;
290 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
292 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
295 void InitGfxCustomArtworkInfo()
297 gfx.override_level_graphics = FALSE;
298 gfx.override_level_sounds = FALSE;
299 gfx.override_level_music = FALSE;
301 gfx.draw_init_text = TRUE;
304 void InitGfxOtherSettings()
306 gfx.cursor_mode = CURSOR_DEFAULT;
309 void InitTileCursorInfo()
311 tile_cursor.enabled = FALSE;
312 tile_cursor.active = FALSE;
313 tile_cursor.moving = FALSE;
315 tile_cursor.xpos = 0;
316 tile_cursor.ypos = 0;
319 tile_cursor.target_x = 0;
320 tile_cursor.target_y = 0;
326 void InitOverlayInfo()
328 int nr = GRID_ACTIVE_NR();
331 overlay.enabled = FALSE;
332 overlay.active = FALSE;
334 overlay.show_grid = FALSE;
336 overlay.grid_xsize = setup.touch.grid_xsize[nr];
337 overlay.grid_ysize = setup.touch.grid_ysize[nr];
339 for (x = 0; x < MAX_GRID_XSIZE; x++)
340 for (y = 0; y < MAX_GRID_YSIZE; y++)
341 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
343 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
344 overlay.grid_button_action = JOY_NO_ACTION;
346 #if defined(USE_TOUCH_INPUT_OVERLAY)
347 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
348 overlay.enabled = TRUE;
352 void SetTileCursorEnabled(boolean enabled)
354 tile_cursor.enabled = enabled;
357 void SetTileCursorActive(boolean active)
359 tile_cursor.active = active;
362 void SetTileCursorTargetXY(int x, int y)
364 // delayed placement of tile selection cursor at target position
365 // (tile cursor will be moved to target position step by step)
367 tile_cursor.xpos = x;
368 tile_cursor.ypos = y;
369 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
370 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
372 tile_cursor.moving = TRUE;
375 void SetTileCursorXY(int x, int y)
377 // immediate placement of tile selection cursor at target position
379 SetTileCursorTargetXY(x, y);
381 tile_cursor.x = tile_cursor.target_x;
382 tile_cursor.y = tile_cursor.target_y;
384 tile_cursor.moving = FALSE;
387 void SetTileCursorSXSY(int sx, int sy)
393 void SetOverlayEnabled(boolean enabled)
395 overlay.enabled = enabled;
398 void SetOverlayActive(boolean active)
400 overlay.active = active;
403 void SetOverlayShowGrid(boolean show_grid)
405 overlay.show_grid = show_grid;
407 SetOverlayActive(show_grid);
410 SetOverlayEnabled(TRUE);
413 boolean GetOverlayActive()
415 return overlay.active;
418 void SetDrawDeactivationMask(int draw_deactivation_mask)
420 gfx.draw_deactivation_mask = draw_deactivation_mask;
423 int GetDrawDeactivationMask()
425 return gfx.draw_deactivation_mask;
428 void SetDrawBackgroundMask(int draw_background_mask)
430 gfx.draw_background_mask = draw_background_mask;
433 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
435 if (background_bitmap_tile != NULL)
436 gfx.background_bitmap_mask |= mask;
438 gfx.background_bitmap_mask &= ~mask;
440 if (background_bitmap_tile == NULL) /* empty background requested */
443 if (mask == REDRAW_ALL)
444 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
445 0, 0, video.width, video.height);
446 else if (mask == REDRAW_FIELD)
447 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
448 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
449 else if (mask == REDRAW_DOOR_1)
450 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
451 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
454 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
456 /* remove every mask before setting mask for window */
457 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
458 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
459 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
462 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
464 /* remove window area mask before setting mask for main area */
465 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
466 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
467 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
470 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
472 /* remove window area mask before setting mask for door area */
473 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
474 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
475 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
479 /* ========================================================================= */
480 /* video functions */
481 /* ========================================================================= */
483 inline static int GetRealDepth(int depth)
485 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
488 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
489 int width, int height, Pixel color)
491 SDLFillRectangle(bitmap, x, y, width, height, color);
493 if (bitmap == backbuffer)
494 SetRedrawMaskFromArea(x, y, width, height);
497 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
498 int src_x, int src_y, int width, int height,
499 int dst_x, int dst_y, int mask_mode)
501 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
502 dst_x, dst_y, mask_mode);
504 if (dst_bitmap == backbuffer)
505 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
508 void LimitScreenUpdates(boolean enable)
510 SDLLimitScreenUpdates(enable);
513 void InitVideoDefaults(void)
515 video.default_depth = 32;
518 void InitVideoDisplay(void)
520 if (program.headless)
523 SDLInitVideoDisplay();
524 #if defined(TARGET_SDL2)
529 void CloseVideoDisplay(void)
531 KeyboardAutoRepeatOn();
533 SDL_QuitSubSystem(SDL_INIT_VIDEO);
536 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
539 video.height = height;
540 video.depth = GetRealDepth(depth);
542 video.screen_width = width;
543 video.screen_height = height;
544 video.screen_xoffset = 0;
545 video.screen_yoffset = 0;
547 video.fullscreen_available = FULLSCREEN_STATUS;
548 video.fullscreen_enabled = FALSE;
550 video.window_scaling_available = WINDOW_SCALING_STATUS;
552 video.frame_delay = 0;
553 video.frame_delay_value = GAME_FRAME_DELAY;
555 video.shifted_up = FALSE;
556 video.shifted_up_pos = 0;
557 video.shifted_up_pos_last = 0;
558 video.shifted_up_delay = 0;
559 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
561 SDLInitVideoBuffer(fullscreen);
563 video.initialized = !program.headless;
568 inline static void FreeBitmapPointers(Bitmap *bitmap)
573 SDLFreeBitmapPointers(bitmap);
575 checked_free(bitmap->source_filename);
576 bitmap->source_filename = NULL;
579 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
582 if (src_bitmap == NULL || dst_bitmap == NULL)
585 FreeBitmapPointers(dst_bitmap);
587 *dst_bitmap = *src_bitmap;
590 void FreeBitmap(Bitmap *bitmap)
595 FreeBitmapPointers(bitmap);
600 Bitmap *CreateBitmapStruct(void)
602 return checked_calloc(sizeof(Bitmap));
605 Bitmap *CreateBitmap(int width, int height, int depth)
607 Bitmap *new_bitmap = CreateBitmapStruct();
608 int real_width = MAX(1, width); /* prevent zero bitmap width */
609 int real_height = MAX(1, height); /* prevent zero bitmap height */
610 int real_depth = GetRealDepth(depth);
612 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
614 new_bitmap->width = real_width;
615 new_bitmap->height = real_height;
620 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
624 /* if new bitmap size fits into old one, no need to re-create it */
625 if (width <= (*bitmap)->width &&
626 height <= (*bitmap)->height)
629 /* else adjust size so that old and new bitmap size fit into it */
630 width = MAX(width, (*bitmap)->width);
631 height = MAX(height, (*bitmap)->height);
634 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
638 *bitmap = new_bitmap;
642 TransferBitmapPointers(new_bitmap, *bitmap);
647 void CloseWindow(DrawWindow *window)
651 void SetRedrawMaskFromArea(int x, int y, int width, int height)
655 int x2 = x + width - 1;
656 int y2 = y + height - 1;
658 if (width == 0 || height == 0)
661 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
662 redraw_mask |= REDRAW_FIELD;
663 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
664 redraw_mask |= REDRAW_DOOR_1;
665 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
666 redraw_mask |= REDRAW_DOOR_2;
667 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
668 redraw_mask |= REDRAW_DOOR_3;
670 redraw_mask = REDRAW_ALL;
673 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
676 if (draw_mask == REDRAW_NONE)
679 if (draw_mask & REDRAW_ALL)
682 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
685 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
688 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
691 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
697 boolean DrawingDeactivatedField()
699 if (program.headless)
702 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
708 boolean DrawingDeactivated(int x, int y, int width, int height)
710 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
713 boolean DrawingOnBackground(int x, int y)
715 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
716 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
719 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
720 int *width, int *height, boolean is_dest)
722 int clip_x, clip_y, clip_width, clip_height;
724 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
726 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
727 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
728 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
729 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
735 clip_width = bitmap->width;
736 clip_height = bitmap->height;
739 /* skip if rectangle completely outside bitmap */
741 if (*x + *width <= clip_x ||
742 *y + *height <= clip_y ||
743 *x >= clip_x + clip_width ||
744 *y >= clip_y + clip_height)
747 /* clip if rectangle overlaps bitmap */
751 *width -= clip_x - *x;
754 else if (*x + *width > clip_x + clip_width)
756 *width = clip_x + clip_width - *x;
761 *height -= clip_y - *y;
764 else if (*y + *height > clip_y + clip_height)
766 *height = clip_y + clip_height - *y;
772 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
773 int src_x, int src_y, int width, int height,
774 int dst_x, int dst_y)
776 int dst_x_unclipped = dst_x;
777 int dst_y_unclipped = dst_y;
779 if (program.headless)
782 if (src_bitmap == NULL || dst_bitmap == NULL)
785 if (DrawingDeactivated(dst_x, dst_y, width, height))
788 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
789 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
792 /* source x/y might need adjustment if destination x/y was clipped top/left */
793 src_x += dst_x - dst_x_unclipped;
794 src_y += dst_y - dst_y_unclipped;
796 #if defined(TARGET_SDL2)
797 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
798 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
799 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
800 but is already fixed in SVN and should therefore finally be fixed with
801 the next official SDL release, which is probably version 1.2.14.) */
802 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
804 if (src_bitmap == dst_bitmap)
806 /* needed when blitting directly to same bitmap -- should not be needed with
807 recent SDL libraries, but apparently does not work in 1.2.11 directly */
809 static Bitmap *tmp_bitmap = NULL;
810 static int tmp_bitmap_xsize = 0;
811 static int tmp_bitmap_ysize = 0;
813 /* start with largest static bitmaps for initial bitmap size ... */
814 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
816 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
817 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
820 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
821 if (src_bitmap->width > tmp_bitmap_xsize ||
822 src_bitmap->height > tmp_bitmap_ysize)
824 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
825 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
827 FreeBitmap(tmp_bitmap);
832 if (tmp_bitmap == NULL)
833 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
836 sysCopyArea(src_bitmap, tmp_bitmap,
837 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
838 sysCopyArea(tmp_bitmap, dst_bitmap,
839 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
845 sysCopyArea(src_bitmap, dst_bitmap,
846 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
849 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
850 int src_x, int src_y, int src_width, int src_height,
851 int dst_x, int dst_y, int dst_width, int dst_height)
853 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
854 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
855 int dst_xsize = dst_width;
856 int dst_ysize = dst_height;
857 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
858 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
861 for (y = 0; y < src_ysteps; y++)
863 for (x = 0; x < src_xsteps; x++)
865 int draw_x = dst_x + x * src_xsize;
866 int draw_y = dst_y + y * src_ysize;
867 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
868 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
870 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
876 void FadeRectangle(int x, int y, int width, int height,
877 int fade_mode, int fade_delay, int post_delay,
878 void (*draw_border_function)(void))
880 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
881 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
884 SDLFadeRectangle(x, y, width, height,
885 fade_mode, fade_delay, post_delay, draw_border_function);
888 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
891 if (DrawingDeactivated(x, y, width, height))
894 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
897 sysFillRectangle(bitmap, x, y, width, height, color);
900 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
902 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
905 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
906 int width, int height)
908 if (DrawingOnBackground(x, y))
909 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
911 ClearRectangle(bitmap, x, y, width, height);
914 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
915 int src_x, int src_y, int width, int height,
916 int dst_x, int dst_y)
918 if (DrawingDeactivated(dst_x, dst_y, width, height))
921 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
922 dst_x, dst_y, BLIT_MASKED);
925 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
926 int src_x, int src_y, int width, int height,
927 int dst_x, int dst_y)
929 if (DrawingOnBackground(dst_x, dst_y))
931 /* draw background */
932 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
935 /* draw foreground */
936 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
940 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
944 void BlitTexture(Bitmap *bitmap,
945 int src_x, int src_y, int width, int height,
946 int dst_x, int dst_y)
951 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
955 void BlitTextureMasked(Bitmap *bitmap,
956 int src_x, int src_y, int width, int height,
957 int dst_x, int dst_y)
962 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
966 void BlitToScreen(Bitmap *bitmap,
967 int src_x, int src_y, int width, int height,
968 int dst_x, int dst_y)
973 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
974 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
975 width, height, dst_x, dst_y);
977 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
980 void BlitToScreenMasked(Bitmap *bitmap,
981 int src_x, int src_y, int width, int height,
982 int dst_x, int dst_y)
987 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
988 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
989 width, height, dst_x, dst_y);
991 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
994 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
997 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1000 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1003 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1006 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1007 int to_x, int to_y, Pixel pixel, int line_width)
1011 if (program.headless)
1014 for (x = 0; x < line_width; x++)
1016 for (y = 0; y < line_width; y++)
1018 int dx = x - line_width / 2;
1019 int dy = y - line_width / 2;
1021 if ((x == 0 && y == 0) ||
1022 (x == 0 && y == line_width - 1) ||
1023 (x == line_width - 1 && y == 0) ||
1024 (x == line_width - 1 && y == line_width - 1))
1028 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1033 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1038 for (i = 0; i < num_points - 1; i++)
1039 DrawLine(bitmap, points[i].x, points[i].y,
1040 points[i + 1].x, points[i + 1].y, pixel, line_width);
1043 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1047 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1049 if (program.headless)
1052 if (x < 0 || x >= bitmap->width ||
1053 y < 0 || y >= bitmap->height)
1056 return SDLGetPixel(bitmap, x, y);
1059 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1060 unsigned int color_g, unsigned int color_b)
1062 if (program.headless)
1065 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1068 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1070 unsigned int color_r = (color >> 16) & 0xff;
1071 unsigned int color_g = (color >> 8) & 0xff;
1072 unsigned int color_b = (color >> 0) & 0xff;
1074 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1077 void KeyboardAutoRepeatOn(void)
1079 #if defined(TARGET_SDL2)
1080 keyrepeat_status = TRUE;
1082 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1083 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1084 SDL_EnableUNICODE(1);
1088 void KeyboardAutoRepeatOff(void)
1090 #if defined(TARGET_SDL2)
1091 keyrepeat_status = FALSE;
1093 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1094 SDL_EnableUNICODE(0);
1098 boolean SetVideoMode(boolean fullscreen)
1100 return SDLSetVideoMode(fullscreen);
1103 void SetVideoFrameDelay(unsigned int frame_delay_value)
1105 video.frame_delay_value = frame_delay_value;
1108 unsigned int GetVideoFrameDelay()
1110 return video.frame_delay_value;
1113 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1115 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1116 (!fullscreen && video.fullscreen_enabled))
1117 fullscreen = SetVideoMode(fullscreen);
1122 Bitmap *LoadImage(char *filename)
1126 new_bitmap = SDLLoadImage(filename);
1129 new_bitmap->source_filename = getStringCopy(filename);
1134 Bitmap *LoadCustomImage(char *basename)
1136 char *filename = getCustomImageFilename(basename);
1139 if (filename == NULL)
1140 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1142 if ((new_bitmap = LoadImage(filename)) == NULL)
1143 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1148 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1150 char *filename = getCustomImageFilename(basename);
1153 if (filename == NULL) /* (should never happen) */
1155 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1159 if (strEqual(filename, bitmap->source_filename))
1161 /* The old and new image are the same (have the same filename and path).
1162 This usually means that this image does not exist in this graphic set
1163 and a fallback to the existing image is done. */
1168 if ((new_bitmap = LoadImage(filename)) == NULL)
1170 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1174 if (bitmap->width != new_bitmap->width ||
1175 bitmap->height != new_bitmap->height)
1177 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1179 FreeBitmap(new_bitmap);
1183 TransferBitmapPointers(new_bitmap, bitmap);
1187 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1189 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1192 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1194 if (bitmaps[IMG_BITMAP_CUSTOM])
1196 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1198 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1201 if (gfx.game_tile_size == gfx.standard_tile_size)
1203 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1208 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1209 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1210 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1212 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1214 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1215 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1218 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1219 int tile_size, boolean create_small_bitmaps)
1221 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1222 Bitmap *tmp_bitmap_final = NULL;
1223 Bitmap *tmp_bitmap_0 = NULL;
1224 Bitmap *tmp_bitmap_1 = NULL;
1225 Bitmap *tmp_bitmap_2 = NULL;
1226 Bitmap *tmp_bitmap_4 = NULL;
1227 Bitmap *tmp_bitmap_8 = NULL;
1228 Bitmap *tmp_bitmap_16 = NULL;
1229 Bitmap *tmp_bitmap_32 = NULL;
1230 int width_final, height_final;
1231 int width_0, height_0;
1232 int width_1, height_1;
1233 int width_2, height_2;
1234 int width_4, height_4;
1235 int width_8, height_8;
1236 int width_16, height_16;
1237 int width_32, height_32;
1238 int old_width, old_height;
1241 print_timestamp_init("CreateScaledBitmaps");
1243 old_width = old_bitmap->width;
1244 old_height = old_bitmap->height;
1246 /* calculate new image dimensions for final image size */
1247 width_final = old_width * zoom_factor;
1248 height_final = old_height * zoom_factor;
1250 /* get image with final size (this might require scaling up) */
1251 /* ("final" size may result in non-standard tile size image) */
1252 if (zoom_factor != 1)
1253 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1255 tmp_bitmap_final = old_bitmap;
1257 UPDATE_BUSY_STATE();
1259 width_0 = width_1 = width_final;
1260 height_0 = height_1 = height_final;
1262 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1264 if (create_small_bitmaps)
1266 /* check if we have a non-gameplay tile size image */
1267 if (tile_size != gfx.game_tile_size)
1269 /* get image with gameplay tile size */
1270 width_0 = width_final * gfx.game_tile_size / tile_size;
1271 height_0 = height_final * gfx.game_tile_size / tile_size;
1273 if (width_0 == old_width)
1274 tmp_bitmap_0 = old_bitmap;
1275 else if (width_0 == width_final)
1276 tmp_bitmap_0 = tmp_bitmap_final;
1278 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1280 UPDATE_BUSY_STATE();
1283 /* check if we have a non-standard tile size image */
1284 if (tile_size != gfx.standard_tile_size)
1286 /* get image with standard tile size */
1287 width_1 = width_final * gfx.standard_tile_size / tile_size;
1288 height_1 = height_final * gfx.standard_tile_size / tile_size;
1290 if (width_1 == old_width)
1291 tmp_bitmap_1 = old_bitmap;
1292 else if (width_1 == width_final)
1293 tmp_bitmap_1 = tmp_bitmap_final;
1294 else if (width_1 == width_0)
1295 tmp_bitmap_1 = tmp_bitmap_0;
1297 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1299 UPDATE_BUSY_STATE();
1302 /* calculate new image dimensions for small images */
1303 width_2 = width_1 / 2;
1304 height_2 = height_1 / 2;
1305 width_4 = width_1 / 4;
1306 height_4 = height_1 / 4;
1307 width_8 = width_1 / 8;
1308 height_8 = height_1 / 8;
1309 width_16 = width_1 / 16;
1310 height_16 = height_1 / 16;
1311 width_32 = width_1 / 32;
1312 height_32 = height_1 / 32;
1314 /* get image with 1/2 of normal size (for use in the level editor) */
1315 if (width_2 == old_width)
1316 tmp_bitmap_2 = old_bitmap;
1318 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1320 UPDATE_BUSY_STATE();
1322 /* get image with 1/4 of normal size (for use in the level editor) */
1323 if (width_4 == old_width)
1324 tmp_bitmap_4 = old_bitmap;
1326 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1328 UPDATE_BUSY_STATE();
1330 /* get image with 1/8 of normal size (for use on the preview screen) */
1331 if (width_8 == old_width)
1332 tmp_bitmap_8 = old_bitmap;
1334 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1336 UPDATE_BUSY_STATE();
1338 /* get image with 1/16 of normal size (for use on the preview screen) */
1339 if (width_16 == old_width)
1340 tmp_bitmap_16 = old_bitmap;
1342 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1344 UPDATE_BUSY_STATE();
1346 /* get image with 1/32 of normal size (for use on the preview screen) */
1347 if (width_32 == old_width)
1348 tmp_bitmap_32 = old_bitmap;
1350 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1352 UPDATE_BUSY_STATE();
1354 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1355 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1356 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1357 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1358 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1359 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1361 if (width_0 != width_1)
1362 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1364 if (bitmaps[IMG_BITMAP_CUSTOM])
1365 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1367 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1369 boolean free_old_bitmap = TRUE;
1371 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1372 if (bitmaps[i] == old_bitmap)
1373 free_old_bitmap = FALSE;
1375 if (free_old_bitmap)
1376 FreeBitmap(old_bitmap);
1380 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1383 UPDATE_BUSY_STATE();
1385 print_timestamp_done("CreateScaledBitmaps");
1388 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1391 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1394 void CreateBitmapTextures(Bitmap **bitmaps)
1396 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1399 void FreeBitmapTextures(Bitmap **bitmaps)
1401 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1404 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1406 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1410 /* ------------------------------------------------------------------------- */
1411 /* mouse pointer functions */
1412 /* ------------------------------------------------------------------------- */
1414 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1416 /* XPM image definitions */
1417 static const char *cursor_image_none[] =
1419 /* width height num_colors chars_per_pixel */
1449 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1450 static const char *cursor_image_dot[] =
1452 /* width height num_colors chars_per_pixel */
1481 static const char **cursor_image_playfield = cursor_image_dot;
1483 /* some people complained about a "white dot" on the screen and thought it
1484 was a graphical error... OK, let's just remove the whole pointer :-) */
1485 static const char **cursor_image_playfield = cursor_image_none;
1488 static const int cursor_bit_order = BIT_ORDER_MSB;
1490 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1492 struct MouseCursorInfo *cursor;
1493 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1494 int header_lines = 4;
1497 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1499 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1502 for (y = 0; y < cursor->width; y++)
1504 for (x = 0; x < cursor->height; x++)
1507 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1512 cursor->data[i] = cursor->mask[i] = 0;
1515 switch (image[header_lines + y][x])
1518 cursor->data[i] |= bit_mask;
1519 cursor->mask[i] |= bit_mask;
1523 cursor->mask[i] |= bit_mask;
1532 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1537 void SetMouseCursor(int mode)
1539 static struct MouseCursorInfo *cursor_none = NULL;
1540 static struct MouseCursorInfo *cursor_playfield = NULL;
1541 struct MouseCursorInfo *cursor_new;
1543 if (cursor_none == NULL)
1544 cursor_none = get_cursor_from_image(cursor_image_none);
1546 if (cursor_playfield == NULL)
1547 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1549 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1550 mode == CURSOR_NONE ? cursor_none :
1551 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1553 SDLSetMouseCursor(cursor_new);
1555 gfx.cursor_mode = mode;
1559 /* ========================================================================= */
1560 /* audio functions */
1561 /* ========================================================================= */
1563 void OpenAudio(void)
1565 /* always start with reliable default values */
1566 audio.sound_available = FALSE;
1567 audio.music_available = FALSE;
1568 audio.loops_available = FALSE;
1570 audio.sound_enabled = FALSE;
1571 audio.sound_deactivated = FALSE;
1573 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1574 audio.mixer_pid = 0;
1575 audio.device_name = NULL;
1576 audio.device_fd = -1;
1578 audio.num_channels = 0;
1579 audio.music_channel = 0;
1580 audio.first_sound_channel = 0;
1585 void CloseAudio(void)
1589 audio.sound_enabled = FALSE;
1592 void SetAudioMode(boolean enabled)
1594 if (!audio.sound_available)
1597 audio.sound_enabled = enabled;
1601 /* ========================================================================= */
1602 /* event functions */
1603 /* ========================================================================= */
1605 boolean PendingEvent(void)
1607 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1610 void WaitEvent(Event *event)
1612 SDLWaitEvent(event);
1615 void PeekEvent(Event *event)
1617 #if defined(TARGET_SDL2)
1618 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1620 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1624 void CheckQuitEvent(void)
1626 if (SDL_QuitRequested())
1627 program.exit_function(0);
1630 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1632 #if defined(TARGET_SDL2)
1633 /* key up/down events in SDL2 do not return text characters anymore */
1634 return event->keysym.sym;
1637 #if ENABLE_UNUSED_CODE
1638 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1639 (int)event->keysym.unicode,
1640 (int)event->keysym.sym,
1641 (int)SDL_GetModState());
1644 if (with_modifiers &&
1645 event->keysym.unicode > 0x0000 &&
1646 event->keysym.unicode < 0x2000)
1647 return event->keysym.unicode;
1649 return event->keysym.sym;
1654 KeyMod HandleKeyModState(Key key, int key_status)
1656 static KeyMod current_modifiers = KMOD_None;
1658 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1660 KeyMod new_modifier = KMOD_None;
1665 new_modifier = KMOD_Shift_L;
1668 new_modifier = KMOD_Shift_R;
1670 case KSYM_Control_L:
1671 new_modifier = KMOD_Control_L;
1673 case KSYM_Control_R:
1674 new_modifier = KMOD_Control_R;
1677 new_modifier = KMOD_Meta_L;
1680 new_modifier = KMOD_Meta_R;
1683 new_modifier = KMOD_Alt_L;
1686 new_modifier = KMOD_Alt_R;
1692 if (key_status == KEY_PRESSED)
1693 current_modifiers |= new_modifier;
1695 current_modifiers &= ~new_modifier;
1698 return current_modifiers;
1701 KeyMod GetKeyModState()
1703 return (KeyMod)SDL_GetModState();
1706 KeyMod GetKeyModStateFromEvents()
1708 /* always use key modifier state as tracked from key events (this is needed
1709 if the modifier key event was injected into the event queue, but the key
1710 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1711 query the keys as held pressed on the keyboard) -- this case is currently
1712 only used to filter out clipboard insert events from "True X-Mouse" tool */
1714 return HandleKeyModState(KSYM_UNDEFINED, 0);
1717 void StartTextInput(int x, int y, int width, int height)
1719 #if defined(TARGET_SDL2)
1720 #if defined(HAS_SCREEN_KEYBOARD)
1721 SDL_StartTextInput();
1723 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1725 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1726 video.shifted_up_delay = SDL_GetTicks();
1727 video.shifted_up = TRUE;
1733 void StopTextInput()
1735 #if defined(TARGET_SDL2)
1736 #if defined(HAS_SCREEN_KEYBOARD)
1737 SDL_StopTextInput();
1739 if (video.shifted_up)
1741 video.shifted_up_pos = 0;
1742 video.shifted_up_delay = SDL_GetTicks();
1743 video.shifted_up = FALSE;
1749 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1751 if (event->type != EVENT_CLIENTMESSAGE)
1754 return TRUE; /* the only possible message here is SDL_QUIT */
1758 /* ========================================================================= */
1759 /* joystick functions */
1760 /* ========================================================================= */
1762 void InitJoysticks()
1766 #if defined(NO_JOYSTICK)
1767 return; /* joysticks generally deactivated by compile-time directive */
1770 /* always start with reliable default values */
1771 joystick.status = JOYSTICK_NOT_AVAILABLE;
1772 for (i = 0; i < MAX_PLAYERS; i++)
1773 joystick.nr[i] = -1; /* no joystick configured */
1778 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1780 return SDLReadJoystick(nr, x, y, b1, b2);
1783 boolean CheckJoystickOpened(int nr)
1785 return SDLCheckJoystickOpened(nr);
1788 void ClearJoystickState()
1790 SDLClearJoystickState();