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 static char *default_grid_button[6][2] =
334 { "111222", " vv " },
337 int nr = GRID_ACTIVE_NR();
340 overlay.enabled = FALSE;
341 overlay.active = FALSE;
343 overlay.show_grid = FALSE;
344 overlay.show_grid_buttons = FALSE;
346 for (i = 0; i < 2; i++)
348 int grid_xsize = DEFAULT_GRID_XSIZE(i);
349 int grid_ysize = DEFAULT_GRID_YSIZE(i);
350 int min_xsize = MIN(6, grid_xsize);
351 int min_ysize = MIN(6, grid_ysize);
352 int startx = grid_xsize - min_xsize;
353 int starty = grid_ysize - min_ysize;
355 overlay.grid_xsize_all[i] = grid_xsize;
356 overlay.grid_ysize_all[i] = grid_ysize;
358 for (x = 0; x < MAX_GRID_XSIZE; x++)
359 for (y = 0; y < MAX_GRID_YSIZE; y++)
360 overlay.grid_button_all[i][x][y] = CHAR_GRID_BUTTON_NONE;
362 for (x = 0; x < min_xsize; x++)
363 for (y = 0; y < min_ysize; y++)
364 overlay.grid_button_all[i][x][starty + y] =
365 default_grid_button[y][0][x];
367 for (x = 0; x < min_xsize; x++)
368 for (y = 0; y < min_ysize; y++)
369 overlay.grid_button_all[i][startx + x][starty + y] =
370 default_grid_button[y][1][x];
373 overlay.grid_xsize = overlay.grid_xsize_all[nr];
374 overlay.grid_ysize = overlay.grid_ysize_all[nr];
376 for (x = 0; x < MAX_GRID_XSIZE; x++)
377 for (y = 0; y < MAX_GRID_YSIZE; y++)
378 overlay.grid_button[x][y] = overlay.grid_button_all[nr][x][y];
380 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
382 #if defined(PLATFORM_ANDROID)
383 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
384 overlay.enabled = TRUE;
388 void SetTileCursorEnabled(boolean enabled)
390 tile_cursor.enabled = enabled;
393 void SetTileCursorActive(boolean active)
395 tile_cursor.active = active;
398 void SetTileCursorTargetXY(int x, int y)
400 // delayed placement of tile selection cursor at target position
401 // (tile cursor will be moved to target position step by step)
403 tile_cursor.xpos = x;
404 tile_cursor.ypos = y;
405 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
406 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
408 tile_cursor.moving = TRUE;
411 void SetTileCursorXY(int x, int y)
413 // immediate placement of tile selection cursor at target position
415 SetTileCursorTargetXY(x, y);
417 tile_cursor.x = tile_cursor.target_x;
418 tile_cursor.y = tile_cursor.target_y;
420 tile_cursor.moving = FALSE;
423 void SetTileCursorSXSY(int sx, int sy)
429 void SetOverlayEnabled(boolean enabled)
431 overlay.enabled = enabled;
434 void SetOverlayActive(boolean active)
436 overlay.active = active;
439 void SetOverlayShowGrid(boolean show_grid)
441 overlay.show_grid = show_grid;
442 overlay.show_grid_buttons = show_grid;
444 SetOverlayActive(show_grid);
447 SetOverlayEnabled(TRUE);
450 boolean GetOverlayActive()
452 return overlay.active;
455 void SetDrawDeactivationMask(int draw_deactivation_mask)
457 gfx.draw_deactivation_mask = draw_deactivation_mask;
460 int GetDrawDeactivationMask()
462 return gfx.draw_deactivation_mask;
465 void SetDrawBackgroundMask(int draw_background_mask)
467 gfx.draw_background_mask = draw_background_mask;
470 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
472 if (background_bitmap_tile != NULL)
473 gfx.background_bitmap_mask |= mask;
475 gfx.background_bitmap_mask &= ~mask;
477 if (background_bitmap_tile == NULL) /* empty background requested */
480 if (mask == REDRAW_ALL)
481 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
482 0, 0, video.width, video.height);
483 else if (mask == REDRAW_FIELD)
484 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
485 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
486 else if (mask == REDRAW_DOOR_1)
487 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
488 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
491 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
493 /* remove every mask before setting mask for window */
494 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
495 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
496 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
499 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
501 /* remove window area mask before setting mask for main area */
502 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
503 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
504 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
507 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
509 /* remove window area mask before setting mask for door area */
510 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
511 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
512 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
516 /* ========================================================================= */
517 /* video functions */
518 /* ========================================================================= */
520 inline static int GetRealDepth(int depth)
522 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
525 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
526 int width, int height, Pixel color)
528 SDLFillRectangle(bitmap, x, y, width, height, color);
530 if (bitmap == backbuffer)
531 SetRedrawMaskFromArea(x, y, width, height);
534 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
535 int src_x, int src_y, int width, int height,
536 int dst_x, int dst_y, int mask_mode)
538 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
539 dst_x, dst_y, mask_mode);
541 if (dst_bitmap == backbuffer)
542 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
545 void LimitScreenUpdates(boolean enable)
547 SDLLimitScreenUpdates(enable);
550 void InitVideoDefaults(void)
552 video.default_depth = 32;
555 void InitVideoDisplay(void)
557 if (program.headless)
560 SDLInitVideoDisplay();
561 #if defined(TARGET_SDL2)
566 void CloseVideoDisplay(void)
568 KeyboardAutoRepeatOn();
570 SDL_QuitSubSystem(SDL_INIT_VIDEO);
573 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
576 video.height = height;
577 video.depth = GetRealDepth(depth);
579 video.screen_width = width;
580 video.screen_height = height;
581 video.screen_xoffset = 0;
582 video.screen_yoffset = 0;
584 video.fullscreen_available = FULLSCREEN_STATUS;
585 video.fullscreen_enabled = FALSE;
587 video.window_scaling_available = WINDOW_SCALING_STATUS;
589 video.frame_delay = 0;
590 video.frame_delay_value = GAME_FRAME_DELAY;
592 video.shifted_up = FALSE;
593 video.shifted_up_pos = 0;
594 video.shifted_up_pos_last = 0;
595 video.shifted_up_delay = 0;
596 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
598 SDLInitVideoBuffer(fullscreen);
600 video.initialized = !program.headless;
605 inline static void FreeBitmapPointers(Bitmap *bitmap)
610 SDLFreeBitmapPointers(bitmap);
612 checked_free(bitmap->source_filename);
613 bitmap->source_filename = NULL;
616 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
619 if (src_bitmap == NULL || dst_bitmap == NULL)
622 FreeBitmapPointers(dst_bitmap);
624 *dst_bitmap = *src_bitmap;
627 void FreeBitmap(Bitmap *bitmap)
632 FreeBitmapPointers(bitmap);
637 Bitmap *CreateBitmapStruct(void)
639 return checked_calloc(sizeof(Bitmap));
642 Bitmap *CreateBitmap(int width, int height, int depth)
644 Bitmap *new_bitmap = CreateBitmapStruct();
645 int real_width = MAX(1, width); /* prevent zero bitmap width */
646 int real_height = MAX(1, height); /* prevent zero bitmap height */
647 int real_depth = GetRealDepth(depth);
649 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
651 new_bitmap->width = real_width;
652 new_bitmap->height = real_height;
657 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
661 /* if new bitmap size fits into old one, no need to re-create it */
662 if (width <= (*bitmap)->width &&
663 height <= (*bitmap)->height)
666 /* else adjust size so that old and new bitmap size fit into it */
667 width = MAX(width, (*bitmap)->width);
668 height = MAX(height, (*bitmap)->height);
671 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
675 *bitmap = new_bitmap;
679 TransferBitmapPointers(new_bitmap, *bitmap);
684 void CloseWindow(DrawWindow *window)
688 void SetRedrawMaskFromArea(int x, int y, int width, int height)
692 int x2 = x + width - 1;
693 int y2 = y + height - 1;
695 if (width == 0 || height == 0)
698 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
699 redraw_mask |= REDRAW_FIELD;
700 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
701 redraw_mask |= REDRAW_DOOR_1;
702 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
703 redraw_mask |= REDRAW_DOOR_2;
704 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
705 redraw_mask |= REDRAW_DOOR_3;
707 redraw_mask = REDRAW_ALL;
710 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
713 if (draw_mask == REDRAW_NONE)
716 if (draw_mask & REDRAW_ALL)
719 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
722 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
725 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
728 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
734 boolean DrawingDeactivatedField()
736 if (program.headless)
739 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
745 boolean DrawingDeactivated(int x, int y, int width, int height)
747 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
750 boolean DrawingOnBackground(int x, int y)
752 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
753 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
756 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
757 int *width, int *height, boolean is_dest)
759 int clip_x, clip_y, clip_width, clip_height;
761 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
763 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
764 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
765 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
766 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
772 clip_width = bitmap->width;
773 clip_height = bitmap->height;
776 /* skip if rectangle completely outside bitmap */
778 if (*x + *width <= clip_x ||
779 *y + *height <= clip_y ||
780 *x >= clip_x + clip_width ||
781 *y >= clip_y + clip_height)
784 /* clip if rectangle overlaps bitmap */
788 *width -= clip_x - *x;
791 else if (*x + *width > clip_x + clip_width)
793 *width = clip_x + clip_width - *x;
798 *height -= clip_y - *y;
801 else if (*y + *height > clip_y + clip_height)
803 *height = clip_y + clip_height - *y;
809 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
810 int src_x, int src_y, int width, int height,
811 int dst_x, int dst_y)
813 int dst_x_unclipped = dst_x;
814 int dst_y_unclipped = dst_y;
816 if (program.headless)
819 if (src_bitmap == NULL || dst_bitmap == NULL)
822 if (DrawingDeactivated(dst_x, dst_y, width, height))
825 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
826 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
829 /* source x/y might need adjustment if destination x/y was clipped top/left */
830 src_x += dst_x - dst_x_unclipped;
831 src_y += dst_y - dst_y_unclipped;
833 #if defined(TARGET_SDL2)
834 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
835 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
836 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
837 but is already fixed in SVN and should therefore finally be fixed with
838 the next official SDL release, which is probably version 1.2.14.) */
839 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
841 if (src_bitmap == dst_bitmap)
843 /* needed when blitting directly to same bitmap -- should not be needed with
844 recent SDL libraries, but apparently does not work in 1.2.11 directly */
846 static Bitmap *tmp_bitmap = NULL;
847 static int tmp_bitmap_xsize = 0;
848 static int tmp_bitmap_ysize = 0;
850 /* start with largest static bitmaps for initial bitmap size ... */
851 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
853 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
854 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
857 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
858 if (src_bitmap->width > tmp_bitmap_xsize ||
859 src_bitmap->height > tmp_bitmap_ysize)
861 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
862 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
864 FreeBitmap(tmp_bitmap);
869 if (tmp_bitmap == NULL)
870 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
873 sysCopyArea(src_bitmap, tmp_bitmap,
874 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
875 sysCopyArea(tmp_bitmap, dst_bitmap,
876 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
882 sysCopyArea(src_bitmap, dst_bitmap,
883 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
886 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
887 int src_x, int src_y, int src_width, int src_height,
888 int dst_x, int dst_y, int dst_width, int dst_height)
890 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
891 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
892 int dst_xsize = dst_width;
893 int dst_ysize = dst_height;
894 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
895 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
898 for (y = 0; y < src_ysteps; y++)
900 for (x = 0; x < src_xsteps; x++)
902 int draw_x = dst_x + x * src_xsize;
903 int draw_y = dst_y + y * src_ysize;
904 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
905 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
907 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
913 void FadeRectangle(int x, int y, int width, int height,
914 int fade_mode, int fade_delay, int post_delay,
915 void (*draw_border_function)(void))
917 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
918 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
921 SDLFadeRectangle(x, y, width, height,
922 fade_mode, fade_delay, post_delay, draw_border_function);
925 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
928 if (DrawingDeactivated(x, y, width, height))
931 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
934 sysFillRectangle(bitmap, x, y, width, height, color);
937 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
939 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
942 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
943 int width, int height)
945 if (DrawingOnBackground(x, y))
946 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
948 ClearRectangle(bitmap, x, y, width, height);
951 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
952 int src_x, int src_y, int width, int height,
953 int dst_x, int dst_y)
955 if (DrawingDeactivated(dst_x, dst_y, width, height))
958 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
959 dst_x, dst_y, BLIT_MASKED);
962 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
963 int src_x, int src_y, int width, int height,
964 int dst_x, int dst_y)
966 if (DrawingOnBackground(dst_x, dst_y))
968 /* draw background */
969 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
972 /* draw foreground */
973 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
977 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
981 void BlitTexture(Bitmap *bitmap,
982 int src_x, int src_y, int width, int height,
983 int dst_x, int dst_y)
988 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
992 void BlitTextureMasked(Bitmap *bitmap,
993 int src_x, int src_y, int width, int height,
994 int dst_x, int dst_y)
999 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1003 void BlitToScreen(Bitmap *bitmap,
1004 int src_x, int src_y, int width, int height,
1005 int dst_x, int dst_y)
1010 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1011 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1012 width, height, dst_x, dst_y);
1014 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1017 void BlitToScreenMasked(Bitmap *bitmap,
1018 int src_x, int src_y, int width, int height,
1019 int dst_x, int dst_y)
1024 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1025 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1026 width, height, dst_x, dst_y);
1028 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1031 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1034 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1037 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1040 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1043 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1044 int to_x, int to_y, Pixel pixel, int line_width)
1048 if (program.headless)
1051 for (x = 0; x < line_width; x++)
1053 for (y = 0; y < line_width; y++)
1055 int dx = x - line_width / 2;
1056 int dy = y - line_width / 2;
1058 if ((x == 0 && y == 0) ||
1059 (x == 0 && y == line_width - 1) ||
1060 (x == line_width - 1 && y == 0) ||
1061 (x == line_width - 1 && y == line_width - 1))
1065 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1070 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1075 for (i = 0; i < num_points - 1; i++)
1076 DrawLine(bitmap, points[i].x, points[i].y,
1077 points[i + 1].x, points[i + 1].y, pixel, line_width);
1080 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1084 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1086 if (program.headless)
1089 if (x < 0 || x >= bitmap->width ||
1090 y < 0 || y >= bitmap->height)
1093 return SDLGetPixel(bitmap, x, y);
1096 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1097 unsigned int color_g, unsigned int color_b)
1099 if (program.headless)
1102 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1105 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1107 unsigned int color_r = (color >> 16) & 0xff;
1108 unsigned int color_g = (color >> 8) & 0xff;
1109 unsigned int color_b = (color >> 0) & 0xff;
1111 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1114 void KeyboardAutoRepeatOn(void)
1116 #if defined(TARGET_SDL2)
1117 keyrepeat_status = TRUE;
1119 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1120 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1121 SDL_EnableUNICODE(1);
1125 void KeyboardAutoRepeatOff(void)
1127 #if defined(TARGET_SDL2)
1128 keyrepeat_status = FALSE;
1130 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1131 SDL_EnableUNICODE(0);
1135 boolean SetVideoMode(boolean fullscreen)
1137 return SDLSetVideoMode(fullscreen);
1140 void SetVideoFrameDelay(unsigned int frame_delay_value)
1142 video.frame_delay_value = frame_delay_value;
1145 unsigned int GetVideoFrameDelay()
1147 return video.frame_delay_value;
1150 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1152 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1153 (!fullscreen && video.fullscreen_enabled))
1154 fullscreen = SetVideoMode(fullscreen);
1159 Bitmap *LoadImage(char *filename)
1163 new_bitmap = SDLLoadImage(filename);
1166 new_bitmap->source_filename = getStringCopy(filename);
1171 Bitmap *LoadCustomImage(char *basename)
1173 char *filename = getCustomImageFilename(basename);
1176 if (filename == NULL)
1177 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1179 if ((new_bitmap = LoadImage(filename)) == NULL)
1180 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1185 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1187 char *filename = getCustomImageFilename(basename);
1190 if (filename == NULL) /* (should never happen) */
1192 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1196 if (strEqual(filename, bitmap->source_filename))
1198 /* The old and new image are the same (have the same filename and path).
1199 This usually means that this image does not exist in this graphic set
1200 and a fallback to the existing image is done. */
1205 if ((new_bitmap = LoadImage(filename)) == NULL)
1207 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1211 if (bitmap->width != new_bitmap->width ||
1212 bitmap->height != new_bitmap->height)
1214 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1216 FreeBitmap(new_bitmap);
1220 TransferBitmapPointers(new_bitmap, bitmap);
1224 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1226 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1229 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1231 if (bitmaps[IMG_BITMAP_CUSTOM])
1233 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1235 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1238 if (gfx.game_tile_size == gfx.standard_tile_size)
1240 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1245 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1246 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1247 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1249 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1251 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1252 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1255 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1256 int tile_size, boolean create_small_bitmaps)
1258 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1259 Bitmap *tmp_bitmap_final = NULL;
1260 Bitmap *tmp_bitmap_0 = NULL;
1261 Bitmap *tmp_bitmap_1 = NULL;
1262 Bitmap *tmp_bitmap_2 = NULL;
1263 Bitmap *tmp_bitmap_4 = NULL;
1264 Bitmap *tmp_bitmap_8 = NULL;
1265 Bitmap *tmp_bitmap_16 = NULL;
1266 Bitmap *tmp_bitmap_32 = NULL;
1267 int width_final, height_final;
1268 int width_0, height_0;
1269 int width_1, height_1;
1270 int width_2, height_2;
1271 int width_4, height_4;
1272 int width_8, height_8;
1273 int width_16, height_16;
1274 int width_32, height_32;
1275 int old_width, old_height;
1278 print_timestamp_init("CreateScaledBitmaps");
1280 old_width = old_bitmap->width;
1281 old_height = old_bitmap->height;
1283 /* calculate new image dimensions for final image size */
1284 width_final = old_width * zoom_factor;
1285 height_final = old_height * zoom_factor;
1287 /* get image with final size (this might require scaling up) */
1288 /* ("final" size may result in non-standard tile size image) */
1289 if (zoom_factor != 1)
1290 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1292 tmp_bitmap_final = old_bitmap;
1294 UPDATE_BUSY_STATE();
1296 width_0 = width_1 = width_final;
1297 height_0 = height_1 = height_final;
1299 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1301 if (create_small_bitmaps)
1303 /* check if we have a non-gameplay tile size image */
1304 if (tile_size != gfx.game_tile_size)
1306 /* get image with gameplay tile size */
1307 width_0 = width_final * gfx.game_tile_size / tile_size;
1308 height_0 = height_final * gfx.game_tile_size / tile_size;
1310 if (width_0 == old_width)
1311 tmp_bitmap_0 = old_bitmap;
1312 else if (width_0 == width_final)
1313 tmp_bitmap_0 = tmp_bitmap_final;
1315 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1317 UPDATE_BUSY_STATE();
1320 /* check if we have a non-standard tile size image */
1321 if (tile_size != gfx.standard_tile_size)
1323 /* get image with standard tile size */
1324 width_1 = width_final * gfx.standard_tile_size / tile_size;
1325 height_1 = height_final * gfx.standard_tile_size / tile_size;
1327 if (width_1 == old_width)
1328 tmp_bitmap_1 = old_bitmap;
1329 else if (width_1 == width_final)
1330 tmp_bitmap_1 = tmp_bitmap_final;
1331 else if (width_1 == width_0)
1332 tmp_bitmap_1 = tmp_bitmap_0;
1334 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1336 UPDATE_BUSY_STATE();
1339 /* calculate new image dimensions for small images */
1340 width_2 = width_1 / 2;
1341 height_2 = height_1 / 2;
1342 width_4 = width_1 / 4;
1343 height_4 = height_1 / 4;
1344 width_8 = width_1 / 8;
1345 height_8 = height_1 / 8;
1346 width_16 = width_1 / 16;
1347 height_16 = height_1 / 16;
1348 width_32 = width_1 / 32;
1349 height_32 = height_1 / 32;
1351 /* get image with 1/2 of normal size (for use in the level editor) */
1352 if (width_2 == old_width)
1353 tmp_bitmap_2 = old_bitmap;
1355 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1357 UPDATE_BUSY_STATE();
1359 /* get image with 1/4 of normal size (for use in the level editor) */
1360 if (width_4 == old_width)
1361 tmp_bitmap_4 = old_bitmap;
1363 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1365 UPDATE_BUSY_STATE();
1367 /* get image with 1/8 of normal size (for use on the preview screen) */
1368 if (width_8 == old_width)
1369 tmp_bitmap_8 = old_bitmap;
1371 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1373 UPDATE_BUSY_STATE();
1375 /* get image with 1/16 of normal size (for use on the preview screen) */
1376 if (width_16 == old_width)
1377 tmp_bitmap_16 = old_bitmap;
1379 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1381 UPDATE_BUSY_STATE();
1383 /* get image with 1/32 of normal size (for use on the preview screen) */
1384 if (width_32 == old_width)
1385 tmp_bitmap_32 = old_bitmap;
1387 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1389 UPDATE_BUSY_STATE();
1391 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1392 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1393 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1394 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1395 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1396 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1398 if (width_0 != width_1)
1399 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1401 if (bitmaps[IMG_BITMAP_CUSTOM])
1402 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1404 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1406 boolean free_old_bitmap = TRUE;
1408 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1409 if (bitmaps[i] == old_bitmap)
1410 free_old_bitmap = FALSE;
1412 if (free_old_bitmap)
1413 FreeBitmap(old_bitmap);
1417 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1420 UPDATE_BUSY_STATE();
1422 print_timestamp_done("CreateScaledBitmaps");
1425 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1428 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1431 void CreateBitmapTextures(Bitmap **bitmaps)
1433 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1436 void FreeBitmapTextures(Bitmap **bitmaps)
1438 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1441 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1443 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1447 /* ------------------------------------------------------------------------- */
1448 /* mouse pointer functions */
1449 /* ------------------------------------------------------------------------- */
1451 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1453 /* XPM image definitions */
1454 static const char *cursor_image_none[] =
1456 /* width height num_colors chars_per_pixel */
1486 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1487 static const char *cursor_image_dot[] =
1489 /* width height num_colors chars_per_pixel */
1518 static const char **cursor_image_playfield = cursor_image_dot;
1520 /* some people complained about a "white dot" on the screen and thought it
1521 was a graphical error... OK, let's just remove the whole pointer :-) */
1522 static const char **cursor_image_playfield = cursor_image_none;
1525 static const int cursor_bit_order = BIT_ORDER_MSB;
1527 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1529 struct MouseCursorInfo *cursor;
1530 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1531 int header_lines = 4;
1534 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1536 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1539 for (y = 0; y < cursor->width; y++)
1541 for (x = 0; x < cursor->height; x++)
1544 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1549 cursor->data[i] = cursor->mask[i] = 0;
1552 switch (image[header_lines + y][x])
1555 cursor->data[i] |= bit_mask;
1556 cursor->mask[i] |= bit_mask;
1560 cursor->mask[i] |= bit_mask;
1569 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1574 void SetMouseCursor(int mode)
1576 static struct MouseCursorInfo *cursor_none = NULL;
1577 static struct MouseCursorInfo *cursor_playfield = NULL;
1578 struct MouseCursorInfo *cursor_new;
1580 if (cursor_none == NULL)
1581 cursor_none = get_cursor_from_image(cursor_image_none);
1583 if (cursor_playfield == NULL)
1584 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1586 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1587 mode == CURSOR_NONE ? cursor_none :
1588 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1590 SDLSetMouseCursor(cursor_new);
1592 gfx.cursor_mode = mode;
1596 /* ========================================================================= */
1597 /* audio functions */
1598 /* ========================================================================= */
1600 void OpenAudio(void)
1602 /* always start with reliable default values */
1603 audio.sound_available = FALSE;
1604 audio.music_available = FALSE;
1605 audio.loops_available = FALSE;
1607 audio.sound_enabled = FALSE;
1608 audio.sound_deactivated = FALSE;
1610 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1611 audio.mixer_pid = 0;
1612 audio.device_name = NULL;
1613 audio.device_fd = -1;
1615 audio.num_channels = 0;
1616 audio.music_channel = 0;
1617 audio.first_sound_channel = 0;
1622 void CloseAudio(void)
1626 audio.sound_enabled = FALSE;
1629 void SetAudioMode(boolean enabled)
1631 if (!audio.sound_available)
1634 audio.sound_enabled = enabled;
1638 /* ========================================================================= */
1639 /* event functions */
1640 /* ========================================================================= */
1642 boolean PendingEvent(void)
1644 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1647 void WaitEvent(Event *event)
1649 SDLWaitEvent(event);
1652 void PeekEvent(Event *event)
1654 #if defined(TARGET_SDL2)
1655 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1657 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1661 void CheckQuitEvent(void)
1663 if (SDL_QuitRequested())
1664 program.exit_function(0);
1667 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1669 #if defined(TARGET_SDL2)
1670 /* key up/down events in SDL2 do not return text characters anymore */
1671 return event->keysym.sym;
1674 #if ENABLE_UNUSED_CODE
1675 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1676 (int)event->keysym.unicode,
1677 (int)event->keysym.sym,
1678 (int)SDL_GetModState());
1681 if (with_modifiers &&
1682 event->keysym.unicode > 0x0000 &&
1683 event->keysym.unicode < 0x2000)
1684 return event->keysym.unicode;
1686 return event->keysym.sym;
1691 KeyMod HandleKeyModState(Key key, int key_status)
1693 static KeyMod current_modifiers = KMOD_None;
1695 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1697 KeyMod new_modifier = KMOD_None;
1702 new_modifier = KMOD_Shift_L;
1705 new_modifier = KMOD_Shift_R;
1707 case KSYM_Control_L:
1708 new_modifier = KMOD_Control_L;
1710 case KSYM_Control_R:
1711 new_modifier = KMOD_Control_R;
1714 new_modifier = KMOD_Meta_L;
1717 new_modifier = KMOD_Meta_R;
1720 new_modifier = KMOD_Alt_L;
1723 new_modifier = KMOD_Alt_R;
1729 if (key_status == KEY_PRESSED)
1730 current_modifiers |= new_modifier;
1732 current_modifiers &= ~new_modifier;
1735 return current_modifiers;
1738 KeyMod GetKeyModState()
1740 return (KeyMod)SDL_GetModState();
1743 KeyMod GetKeyModStateFromEvents()
1745 /* always use key modifier state as tracked from key events (this is needed
1746 if the modifier key event was injected into the event queue, but the key
1747 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1748 query the keys as held pressed on the keyboard) -- this case is currently
1749 only used to filter out clipboard insert events from "True X-Mouse" tool */
1751 return HandleKeyModState(KSYM_UNDEFINED, 0);
1754 void StartTextInput(int x, int y, int width, int height)
1756 #if defined(TARGET_SDL2)
1757 #if defined(HAS_SCREEN_KEYBOARD)
1758 SDL_StartTextInput();
1760 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1762 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1763 video.shifted_up_delay = SDL_GetTicks();
1764 video.shifted_up = TRUE;
1770 void StopTextInput()
1772 #if defined(TARGET_SDL2)
1773 #if defined(HAS_SCREEN_KEYBOARD)
1774 SDL_StopTextInput();
1776 if (video.shifted_up)
1778 video.shifted_up_pos = 0;
1779 video.shifted_up_delay = SDL_GetTicks();
1780 video.shifted_up = FALSE;
1786 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1788 if (event->type != EVENT_CLIENTMESSAGE)
1791 return TRUE; /* the only possible message here is SDL_QUIT */
1795 /* ========================================================================= */
1796 /* joystick functions */
1797 /* ========================================================================= */
1799 void InitJoysticks()
1803 #if defined(NO_JOYSTICK)
1804 return; /* joysticks generally deactivated by compile-time directive */
1807 /* always start with reliable default values */
1808 joystick.status = JOYSTICK_NOT_AVAILABLE;
1809 for (i = 0; i < MAX_PLAYERS; i++)
1810 joystick.nr[i] = -1; /* no joystick configured */
1815 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1817 return SDLReadJoystick(nr, x, y, b1, b2);
1820 boolean CheckJoystickOpened(int nr)
1822 return SDLCheckJoystickOpened(nr);
1825 void ClearJoystickState()
1827 SDLClearJoystickState();