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;
345 #if defined(USE_TOUCH_INPUT_OVERLAY)
346 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
347 overlay.enabled = TRUE;
351 void SetTileCursorEnabled(boolean enabled)
353 tile_cursor.enabled = enabled;
356 void SetTileCursorActive(boolean active)
358 tile_cursor.active = active;
361 void SetTileCursorTargetXY(int x, int y)
363 // delayed placement of tile selection cursor at target position
364 // (tile cursor will be moved to target position step by step)
366 tile_cursor.xpos = x;
367 tile_cursor.ypos = y;
368 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
369 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
371 tile_cursor.moving = TRUE;
374 void SetTileCursorXY(int x, int y)
376 // immediate placement of tile selection cursor at target position
378 SetTileCursorTargetXY(x, y);
380 tile_cursor.x = tile_cursor.target_x;
381 tile_cursor.y = tile_cursor.target_y;
383 tile_cursor.moving = FALSE;
386 void SetTileCursorSXSY(int sx, int sy)
392 void SetOverlayEnabled(boolean enabled)
394 overlay.enabled = enabled;
397 void SetOverlayActive(boolean active)
399 overlay.active = active;
402 void SetOverlayShowGrid(boolean show_grid)
404 overlay.show_grid = show_grid;
406 SetOverlayActive(show_grid);
409 SetOverlayEnabled(TRUE);
412 boolean GetOverlayActive()
414 return overlay.active;
417 void SetDrawDeactivationMask(int draw_deactivation_mask)
419 gfx.draw_deactivation_mask = draw_deactivation_mask;
422 int GetDrawDeactivationMask()
424 return gfx.draw_deactivation_mask;
427 void SetDrawBackgroundMask(int draw_background_mask)
429 gfx.draw_background_mask = draw_background_mask;
432 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
434 if (background_bitmap_tile != NULL)
435 gfx.background_bitmap_mask |= mask;
437 gfx.background_bitmap_mask &= ~mask;
439 if (background_bitmap_tile == NULL) /* empty background requested */
442 if (mask == REDRAW_ALL)
443 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
444 0, 0, video.width, video.height);
445 else if (mask == REDRAW_FIELD)
446 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
447 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
448 else if (mask == REDRAW_DOOR_1)
449 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
450 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
453 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
455 /* remove every mask before setting mask for window */
456 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
457 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
458 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
461 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
463 /* remove window area mask before setting mask for main area */
464 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
465 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
466 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
469 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
471 /* remove window area mask before setting mask for door area */
472 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
473 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
474 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
478 /* ========================================================================= */
479 /* video functions */
480 /* ========================================================================= */
482 inline static int GetRealDepth(int depth)
484 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
487 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
488 int width, int height, Pixel color)
490 SDLFillRectangle(bitmap, x, y, width, height, color);
492 if (bitmap == backbuffer)
493 SetRedrawMaskFromArea(x, y, width, height);
496 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
497 int src_x, int src_y, int width, int height,
498 int dst_x, int dst_y, int mask_mode)
500 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
501 dst_x, dst_y, mask_mode);
503 if (dst_bitmap == backbuffer)
504 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
507 void LimitScreenUpdates(boolean enable)
509 SDLLimitScreenUpdates(enable);
512 void InitVideoDefaults(void)
514 video.default_depth = 32;
517 void InitVideoDisplay(void)
519 if (program.headless)
522 SDLInitVideoDisplay();
523 #if defined(TARGET_SDL2)
528 void CloseVideoDisplay(void)
530 KeyboardAutoRepeatOn();
532 SDL_QuitSubSystem(SDL_INIT_VIDEO);
535 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
538 video.height = height;
539 video.depth = GetRealDepth(depth);
541 video.screen_width = width;
542 video.screen_height = height;
543 video.screen_xoffset = 0;
544 video.screen_yoffset = 0;
546 video.fullscreen_available = FULLSCREEN_STATUS;
547 video.fullscreen_enabled = FALSE;
549 video.window_scaling_available = WINDOW_SCALING_STATUS;
551 video.frame_delay = 0;
552 video.frame_delay_value = GAME_FRAME_DELAY;
554 video.shifted_up = FALSE;
555 video.shifted_up_pos = 0;
556 video.shifted_up_pos_last = 0;
557 video.shifted_up_delay = 0;
558 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
560 SDLInitVideoBuffer(fullscreen);
562 video.initialized = !program.headless;
567 inline static void FreeBitmapPointers(Bitmap *bitmap)
572 SDLFreeBitmapPointers(bitmap);
574 checked_free(bitmap->source_filename);
575 bitmap->source_filename = NULL;
578 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
581 if (src_bitmap == NULL || dst_bitmap == NULL)
584 FreeBitmapPointers(dst_bitmap);
586 *dst_bitmap = *src_bitmap;
589 void FreeBitmap(Bitmap *bitmap)
594 FreeBitmapPointers(bitmap);
599 Bitmap *CreateBitmapStruct(void)
601 return checked_calloc(sizeof(Bitmap));
604 Bitmap *CreateBitmap(int width, int height, int depth)
606 Bitmap *new_bitmap = CreateBitmapStruct();
607 int real_width = MAX(1, width); /* prevent zero bitmap width */
608 int real_height = MAX(1, height); /* prevent zero bitmap height */
609 int real_depth = GetRealDepth(depth);
611 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
613 new_bitmap->width = real_width;
614 new_bitmap->height = real_height;
619 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
623 /* if new bitmap size fits into old one, no need to re-create it */
624 if (width <= (*bitmap)->width &&
625 height <= (*bitmap)->height)
628 /* else adjust size so that old and new bitmap size fit into it */
629 width = MAX(width, (*bitmap)->width);
630 height = MAX(height, (*bitmap)->height);
633 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
637 *bitmap = new_bitmap;
641 TransferBitmapPointers(new_bitmap, *bitmap);
646 void CloseWindow(DrawWindow *window)
650 void SetRedrawMaskFromArea(int x, int y, int width, int height)
654 int x2 = x + width - 1;
655 int y2 = y + height - 1;
657 if (width == 0 || height == 0)
660 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
661 redraw_mask |= REDRAW_FIELD;
662 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
663 redraw_mask |= REDRAW_DOOR_1;
664 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
665 redraw_mask |= REDRAW_DOOR_2;
666 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
667 redraw_mask |= REDRAW_DOOR_3;
669 redraw_mask = REDRAW_ALL;
672 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
675 if (draw_mask == REDRAW_NONE)
678 if (draw_mask & REDRAW_ALL)
681 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
684 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
687 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
690 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
696 boolean DrawingDeactivatedField()
698 if (program.headless)
701 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
707 boolean DrawingDeactivated(int x, int y, int width, int height)
709 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
712 boolean DrawingOnBackground(int x, int y)
714 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
715 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
718 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
719 int *width, int *height, boolean is_dest)
721 int clip_x, clip_y, clip_width, clip_height;
723 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
725 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
726 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
727 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
728 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
734 clip_width = bitmap->width;
735 clip_height = bitmap->height;
738 /* skip if rectangle completely outside bitmap */
740 if (*x + *width <= clip_x ||
741 *y + *height <= clip_y ||
742 *x >= clip_x + clip_width ||
743 *y >= clip_y + clip_height)
746 /* clip if rectangle overlaps bitmap */
750 *width -= clip_x - *x;
753 else if (*x + *width > clip_x + clip_width)
755 *width = clip_x + clip_width - *x;
760 *height -= clip_y - *y;
763 else if (*y + *height > clip_y + clip_height)
765 *height = clip_y + clip_height - *y;
771 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
772 int src_x, int src_y, int width, int height,
773 int dst_x, int dst_y)
775 int dst_x_unclipped = dst_x;
776 int dst_y_unclipped = dst_y;
778 if (program.headless)
781 if (src_bitmap == NULL || dst_bitmap == NULL)
784 if (DrawingDeactivated(dst_x, dst_y, width, height))
787 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
788 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
791 /* source x/y might need adjustment if destination x/y was clipped top/left */
792 src_x += dst_x - dst_x_unclipped;
793 src_y += dst_y - dst_y_unclipped;
795 #if defined(TARGET_SDL2)
796 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
797 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
798 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
799 but is already fixed in SVN and should therefore finally be fixed with
800 the next official SDL release, which is probably version 1.2.14.) */
801 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
803 if (src_bitmap == dst_bitmap)
805 /* needed when blitting directly to same bitmap -- should not be needed with
806 recent SDL libraries, but apparently does not work in 1.2.11 directly */
808 static Bitmap *tmp_bitmap = NULL;
809 static int tmp_bitmap_xsize = 0;
810 static int tmp_bitmap_ysize = 0;
812 /* start with largest static bitmaps for initial bitmap size ... */
813 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
815 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
816 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
819 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
820 if (src_bitmap->width > tmp_bitmap_xsize ||
821 src_bitmap->height > tmp_bitmap_ysize)
823 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
824 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
826 FreeBitmap(tmp_bitmap);
831 if (tmp_bitmap == NULL)
832 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
835 sysCopyArea(src_bitmap, tmp_bitmap,
836 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
837 sysCopyArea(tmp_bitmap, dst_bitmap,
838 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
844 sysCopyArea(src_bitmap, dst_bitmap,
845 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
848 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
849 int src_x, int src_y, int src_width, int src_height,
850 int dst_x, int dst_y, int dst_width, int dst_height)
852 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
853 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
854 int dst_xsize = dst_width;
855 int dst_ysize = dst_height;
856 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
857 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
860 for (y = 0; y < src_ysteps; y++)
862 for (x = 0; x < src_xsteps; x++)
864 int draw_x = dst_x + x * src_xsize;
865 int draw_y = dst_y + y * src_ysize;
866 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
867 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
869 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
875 void FadeRectangle(int x, int y, int width, int height,
876 int fade_mode, int fade_delay, int post_delay,
877 void (*draw_border_function)(void))
879 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
880 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
883 SDLFadeRectangle(x, y, width, height,
884 fade_mode, fade_delay, post_delay, draw_border_function);
887 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
890 if (DrawingDeactivated(x, y, width, height))
893 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
896 sysFillRectangle(bitmap, x, y, width, height, color);
899 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
901 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
904 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
905 int width, int height)
907 if (DrawingOnBackground(x, y))
908 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
910 ClearRectangle(bitmap, x, y, width, height);
913 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
914 int src_x, int src_y, int width, int height,
915 int dst_x, int dst_y)
917 if (DrawingDeactivated(dst_x, dst_y, width, height))
920 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
921 dst_x, dst_y, BLIT_MASKED);
924 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
925 int src_x, int src_y, int width, int height,
926 int dst_x, int dst_y)
928 if (DrawingOnBackground(dst_x, dst_y))
930 /* draw background */
931 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
934 /* draw foreground */
935 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
939 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
943 void BlitTexture(Bitmap *bitmap,
944 int src_x, int src_y, int width, int height,
945 int dst_x, int dst_y)
950 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
954 void BlitTextureMasked(Bitmap *bitmap,
955 int src_x, int src_y, int width, int height,
956 int dst_x, int dst_y)
961 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
965 void BlitToScreen(Bitmap *bitmap,
966 int src_x, int src_y, int width, int height,
967 int dst_x, int dst_y)
972 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
973 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
974 width, height, dst_x, dst_y);
976 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
979 void BlitToScreenMasked(Bitmap *bitmap,
980 int src_x, int src_y, int width, int height,
981 int dst_x, int dst_y)
986 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
987 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
988 width, height, dst_x, dst_y);
990 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
993 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
996 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
999 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1002 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1005 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1006 int to_x, int to_y, Pixel pixel, int line_width)
1010 if (program.headless)
1013 for (x = 0; x < line_width; x++)
1015 for (y = 0; y < line_width; y++)
1017 int dx = x - line_width / 2;
1018 int dy = y - line_width / 2;
1020 if ((x == 0 && y == 0) ||
1021 (x == 0 && y == line_width - 1) ||
1022 (x == line_width - 1 && y == 0) ||
1023 (x == line_width - 1 && y == line_width - 1))
1027 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1032 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1037 for (i = 0; i < num_points - 1; i++)
1038 DrawLine(bitmap, points[i].x, points[i].y,
1039 points[i + 1].x, points[i + 1].y, pixel, line_width);
1042 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1046 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1048 if (program.headless)
1051 if (x < 0 || x >= bitmap->width ||
1052 y < 0 || y >= bitmap->height)
1055 return SDLGetPixel(bitmap, x, y);
1058 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1059 unsigned int color_g, unsigned int color_b)
1061 if (program.headless)
1064 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1067 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1069 unsigned int color_r = (color >> 16) & 0xff;
1070 unsigned int color_g = (color >> 8) & 0xff;
1071 unsigned int color_b = (color >> 0) & 0xff;
1073 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1076 void KeyboardAutoRepeatOn(void)
1078 #if defined(TARGET_SDL2)
1079 keyrepeat_status = TRUE;
1081 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1082 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1083 SDL_EnableUNICODE(1);
1087 void KeyboardAutoRepeatOff(void)
1089 #if defined(TARGET_SDL2)
1090 keyrepeat_status = FALSE;
1092 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1093 SDL_EnableUNICODE(0);
1097 boolean SetVideoMode(boolean fullscreen)
1099 return SDLSetVideoMode(fullscreen);
1102 void SetVideoFrameDelay(unsigned int frame_delay_value)
1104 video.frame_delay_value = frame_delay_value;
1107 unsigned int GetVideoFrameDelay()
1109 return video.frame_delay_value;
1112 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1114 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1115 (!fullscreen && video.fullscreen_enabled))
1116 fullscreen = SetVideoMode(fullscreen);
1121 Bitmap *LoadImage(char *filename)
1125 new_bitmap = SDLLoadImage(filename);
1128 new_bitmap->source_filename = getStringCopy(filename);
1133 Bitmap *LoadCustomImage(char *basename)
1135 char *filename = getCustomImageFilename(basename);
1138 if (filename == NULL)
1139 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1141 if ((new_bitmap = LoadImage(filename)) == NULL)
1142 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1147 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1149 char *filename = getCustomImageFilename(basename);
1152 if (filename == NULL) /* (should never happen) */
1154 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1158 if (strEqual(filename, bitmap->source_filename))
1160 /* The old and new image are the same (have the same filename and path).
1161 This usually means that this image does not exist in this graphic set
1162 and a fallback to the existing image is done. */
1167 if ((new_bitmap = LoadImage(filename)) == NULL)
1169 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1173 if (bitmap->width != new_bitmap->width ||
1174 bitmap->height != new_bitmap->height)
1176 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1178 FreeBitmap(new_bitmap);
1182 TransferBitmapPointers(new_bitmap, bitmap);
1186 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1188 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1191 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1193 if (bitmaps[IMG_BITMAP_CUSTOM])
1195 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1197 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1200 if (gfx.game_tile_size == gfx.standard_tile_size)
1202 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1207 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1208 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1209 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1211 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1213 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1214 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1217 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1218 int tile_size, boolean create_small_bitmaps)
1220 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1221 Bitmap *tmp_bitmap_final = NULL;
1222 Bitmap *tmp_bitmap_0 = NULL;
1223 Bitmap *tmp_bitmap_1 = NULL;
1224 Bitmap *tmp_bitmap_2 = NULL;
1225 Bitmap *tmp_bitmap_4 = NULL;
1226 Bitmap *tmp_bitmap_8 = NULL;
1227 Bitmap *tmp_bitmap_16 = NULL;
1228 Bitmap *tmp_bitmap_32 = NULL;
1229 int width_final, height_final;
1230 int width_0, height_0;
1231 int width_1, height_1;
1232 int width_2, height_2;
1233 int width_4, height_4;
1234 int width_8, height_8;
1235 int width_16, height_16;
1236 int width_32, height_32;
1237 int old_width, old_height;
1240 print_timestamp_init("CreateScaledBitmaps");
1242 old_width = old_bitmap->width;
1243 old_height = old_bitmap->height;
1245 /* calculate new image dimensions for final image size */
1246 width_final = old_width * zoom_factor;
1247 height_final = old_height * zoom_factor;
1249 /* get image with final size (this might require scaling up) */
1250 /* ("final" size may result in non-standard tile size image) */
1251 if (zoom_factor != 1)
1252 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1254 tmp_bitmap_final = old_bitmap;
1256 UPDATE_BUSY_STATE();
1258 width_0 = width_1 = width_final;
1259 height_0 = height_1 = height_final;
1261 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1263 if (create_small_bitmaps)
1265 /* check if we have a non-gameplay tile size image */
1266 if (tile_size != gfx.game_tile_size)
1268 /* get image with gameplay tile size */
1269 width_0 = width_final * gfx.game_tile_size / tile_size;
1270 height_0 = height_final * gfx.game_tile_size / tile_size;
1272 if (width_0 == old_width)
1273 tmp_bitmap_0 = old_bitmap;
1274 else if (width_0 == width_final)
1275 tmp_bitmap_0 = tmp_bitmap_final;
1277 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1279 UPDATE_BUSY_STATE();
1282 /* check if we have a non-standard tile size image */
1283 if (tile_size != gfx.standard_tile_size)
1285 /* get image with standard tile size */
1286 width_1 = width_final * gfx.standard_tile_size / tile_size;
1287 height_1 = height_final * gfx.standard_tile_size / tile_size;
1289 if (width_1 == old_width)
1290 tmp_bitmap_1 = old_bitmap;
1291 else if (width_1 == width_final)
1292 tmp_bitmap_1 = tmp_bitmap_final;
1293 else if (width_1 == width_0)
1294 tmp_bitmap_1 = tmp_bitmap_0;
1296 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1298 UPDATE_BUSY_STATE();
1301 /* calculate new image dimensions for small images */
1302 width_2 = width_1 / 2;
1303 height_2 = height_1 / 2;
1304 width_4 = width_1 / 4;
1305 height_4 = height_1 / 4;
1306 width_8 = width_1 / 8;
1307 height_8 = height_1 / 8;
1308 width_16 = width_1 / 16;
1309 height_16 = height_1 / 16;
1310 width_32 = width_1 / 32;
1311 height_32 = height_1 / 32;
1313 /* get image with 1/2 of normal size (for use in the level editor) */
1314 if (width_2 == old_width)
1315 tmp_bitmap_2 = old_bitmap;
1317 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1319 UPDATE_BUSY_STATE();
1321 /* get image with 1/4 of normal size (for use in the level editor) */
1322 if (width_4 == old_width)
1323 tmp_bitmap_4 = old_bitmap;
1325 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1327 UPDATE_BUSY_STATE();
1329 /* get image with 1/8 of normal size (for use on the preview screen) */
1330 if (width_8 == old_width)
1331 tmp_bitmap_8 = old_bitmap;
1333 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1335 UPDATE_BUSY_STATE();
1337 /* get image with 1/16 of normal size (for use on the preview screen) */
1338 if (width_16 == old_width)
1339 tmp_bitmap_16 = old_bitmap;
1341 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1343 UPDATE_BUSY_STATE();
1345 /* get image with 1/32 of normal size (for use on the preview screen) */
1346 if (width_32 == old_width)
1347 tmp_bitmap_32 = old_bitmap;
1349 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1351 UPDATE_BUSY_STATE();
1353 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1354 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1355 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1356 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1357 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1358 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1360 if (width_0 != width_1)
1361 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1363 if (bitmaps[IMG_BITMAP_CUSTOM])
1364 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1366 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1368 boolean free_old_bitmap = TRUE;
1370 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1371 if (bitmaps[i] == old_bitmap)
1372 free_old_bitmap = FALSE;
1374 if (free_old_bitmap)
1375 FreeBitmap(old_bitmap);
1379 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1382 UPDATE_BUSY_STATE();
1384 print_timestamp_done("CreateScaledBitmaps");
1387 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1390 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1393 void CreateBitmapTextures(Bitmap **bitmaps)
1395 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1398 void FreeBitmapTextures(Bitmap **bitmaps)
1400 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1403 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1405 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1409 /* ------------------------------------------------------------------------- */
1410 /* mouse pointer functions */
1411 /* ------------------------------------------------------------------------- */
1413 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1415 /* XPM image definitions */
1416 static const char *cursor_image_none[] =
1418 /* width height num_colors chars_per_pixel */
1448 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1449 static const char *cursor_image_dot[] =
1451 /* width height num_colors chars_per_pixel */
1480 static const char **cursor_image_playfield = cursor_image_dot;
1482 /* some people complained about a "white dot" on the screen and thought it
1483 was a graphical error... OK, let's just remove the whole pointer :-) */
1484 static const char **cursor_image_playfield = cursor_image_none;
1487 static const int cursor_bit_order = BIT_ORDER_MSB;
1489 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1491 struct MouseCursorInfo *cursor;
1492 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1493 int header_lines = 4;
1496 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1498 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1501 for (y = 0; y < cursor->width; y++)
1503 for (x = 0; x < cursor->height; x++)
1506 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1511 cursor->data[i] = cursor->mask[i] = 0;
1514 switch (image[header_lines + y][x])
1517 cursor->data[i] |= bit_mask;
1518 cursor->mask[i] |= bit_mask;
1522 cursor->mask[i] |= bit_mask;
1531 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1536 void SetMouseCursor(int mode)
1538 static struct MouseCursorInfo *cursor_none = NULL;
1539 static struct MouseCursorInfo *cursor_playfield = NULL;
1540 struct MouseCursorInfo *cursor_new;
1542 if (cursor_none == NULL)
1543 cursor_none = get_cursor_from_image(cursor_image_none);
1545 if (cursor_playfield == NULL)
1546 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1548 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1549 mode == CURSOR_NONE ? cursor_none :
1550 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1552 SDLSetMouseCursor(cursor_new);
1554 gfx.cursor_mode = mode;
1558 /* ========================================================================= */
1559 /* audio functions */
1560 /* ========================================================================= */
1562 void OpenAudio(void)
1564 /* always start with reliable default values */
1565 audio.sound_available = FALSE;
1566 audio.music_available = FALSE;
1567 audio.loops_available = FALSE;
1569 audio.sound_enabled = FALSE;
1570 audio.sound_deactivated = FALSE;
1572 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1573 audio.mixer_pid = 0;
1574 audio.device_name = NULL;
1575 audio.device_fd = -1;
1577 audio.num_channels = 0;
1578 audio.music_channel = 0;
1579 audio.first_sound_channel = 0;
1584 void CloseAudio(void)
1588 audio.sound_enabled = FALSE;
1591 void SetAudioMode(boolean enabled)
1593 if (!audio.sound_available)
1596 audio.sound_enabled = enabled;
1600 /* ========================================================================= */
1601 /* event functions */
1602 /* ========================================================================= */
1604 boolean PendingEvent(void)
1606 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1609 void WaitEvent(Event *event)
1611 SDLWaitEvent(event);
1614 void PeekEvent(Event *event)
1616 #if defined(TARGET_SDL2)
1617 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1619 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1623 void CheckQuitEvent(void)
1625 if (SDL_QuitRequested())
1626 program.exit_function(0);
1629 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1631 #if defined(TARGET_SDL2)
1632 /* key up/down events in SDL2 do not return text characters anymore */
1633 return event->keysym.sym;
1636 #if ENABLE_UNUSED_CODE
1637 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1638 (int)event->keysym.unicode,
1639 (int)event->keysym.sym,
1640 (int)SDL_GetModState());
1643 if (with_modifiers &&
1644 event->keysym.unicode > 0x0000 &&
1645 event->keysym.unicode < 0x2000)
1646 return event->keysym.unicode;
1648 return event->keysym.sym;
1653 KeyMod HandleKeyModState(Key key, int key_status)
1655 static KeyMod current_modifiers = KMOD_None;
1657 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1659 KeyMod new_modifier = KMOD_None;
1664 new_modifier = KMOD_Shift_L;
1667 new_modifier = KMOD_Shift_R;
1669 case KSYM_Control_L:
1670 new_modifier = KMOD_Control_L;
1672 case KSYM_Control_R:
1673 new_modifier = KMOD_Control_R;
1676 new_modifier = KMOD_Meta_L;
1679 new_modifier = KMOD_Meta_R;
1682 new_modifier = KMOD_Alt_L;
1685 new_modifier = KMOD_Alt_R;
1691 if (key_status == KEY_PRESSED)
1692 current_modifiers |= new_modifier;
1694 current_modifiers &= ~new_modifier;
1697 return current_modifiers;
1700 KeyMod GetKeyModState()
1702 return (KeyMod)SDL_GetModState();
1705 KeyMod GetKeyModStateFromEvents()
1707 /* always use key modifier state as tracked from key events (this is needed
1708 if the modifier key event was injected into the event queue, but the key
1709 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1710 query the keys as held pressed on the keyboard) -- this case is currently
1711 only used to filter out clipboard insert events from "True X-Mouse" tool */
1713 return HandleKeyModState(KSYM_UNDEFINED, 0);
1716 void StartTextInput(int x, int y, int width, int height)
1718 #if defined(TARGET_SDL2)
1719 #if defined(HAS_SCREEN_KEYBOARD)
1720 SDL_StartTextInput();
1722 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1724 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1725 video.shifted_up_delay = SDL_GetTicks();
1726 video.shifted_up = TRUE;
1732 void StopTextInput()
1734 #if defined(TARGET_SDL2)
1735 #if defined(HAS_SCREEN_KEYBOARD)
1736 SDL_StopTextInput();
1738 if (video.shifted_up)
1740 video.shifted_up_pos = 0;
1741 video.shifted_up_delay = SDL_GetTicks();
1742 video.shifted_up = FALSE;
1748 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1750 if (event->type != EVENT_CLIENTMESSAGE)
1753 return TRUE; /* the only possible message here is SDL_QUIT */
1757 /* ========================================================================= */
1758 /* joystick functions */
1759 /* ========================================================================= */
1761 void InitJoysticks()
1765 #if defined(NO_JOYSTICK)
1766 return; /* joysticks generally deactivated by compile-time directive */
1769 /* always start with reliable default values */
1770 joystick.status = JOYSTICK_NOT_AVAILABLE;
1771 for (i = 0; i < MAX_PLAYERS; i++)
1772 joystick.nr[i] = -1; /* no joystick configured */
1777 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1779 return SDLReadJoystick(nr, x, y, b1, b2);
1782 boolean CheckJoystickOpened(int nr)
1784 return SDLCheckJoystickOpened(nr);
1787 void ClearJoystickState()
1789 SDLClearJoystickState();