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;
345 for (i = 0; i < 2; i++)
347 int grid_xsize = DEFAULT_GRID_XSIZE(i);
348 int grid_ysize = DEFAULT_GRID_YSIZE(i);
349 int min_xsize = MIN(6, grid_xsize);
350 int min_ysize = MIN(6, grid_ysize);
351 int startx = grid_xsize - min_xsize;
352 int starty = grid_ysize - min_ysize;
354 overlay.grid_xsize_all[i] = grid_xsize;
355 overlay.grid_ysize_all[i] = grid_ysize;
357 for (x = 0; x < MAX_GRID_XSIZE; x++)
358 for (y = 0; y < MAX_GRID_YSIZE; y++)
359 overlay.grid_button_all[i][x][y] = CHAR_GRID_BUTTON_NONE;
361 for (x = 0; x < min_xsize; x++)
362 for (y = 0; y < min_ysize; y++)
363 overlay.grid_button_all[i][x][starty + y] =
364 default_grid_button[y][0][x];
366 for (x = 0; x < min_xsize; x++)
367 for (y = 0; y < min_ysize; y++)
368 overlay.grid_button_all[i][startx + x][starty + y] =
369 default_grid_button[y][1][x];
372 overlay.grid_xsize = overlay.grid_xsize_all[nr];
373 overlay.grid_ysize = overlay.grid_ysize_all[nr];
375 for (x = 0; x < MAX_GRID_XSIZE; x++)
376 for (y = 0; y < MAX_GRID_YSIZE; y++)
377 overlay.grid_button[x][y] = overlay.grid_button_all[nr][x][y];
379 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
381 #if defined(PLATFORM_ANDROID)
382 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
383 overlay.enabled = TRUE;
387 void SetTileCursorEnabled(boolean enabled)
389 tile_cursor.enabled = enabled;
392 void SetTileCursorActive(boolean active)
394 tile_cursor.active = active;
397 void SetTileCursorTargetXY(int x, int y)
399 // delayed placement of tile selection cursor at target position
400 // (tile cursor will be moved to target position step by step)
402 tile_cursor.xpos = x;
403 tile_cursor.ypos = y;
404 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
405 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
407 tile_cursor.moving = TRUE;
410 void SetTileCursorXY(int x, int y)
412 // immediate placement of tile selection cursor at target position
414 SetTileCursorTargetXY(x, y);
416 tile_cursor.x = tile_cursor.target_x;
417 tile_cursor.y = tile_cursor.target_y;
419 tile_cursor.moving = FALSE;
422 void SetTileCursorSXSY(int sx, int sy)
428 void SetOverlayEnabled(boolean enabled)
430 overlay.enabled = enabled;
433 void SetOverlayActive(boolean active)
435 overlay.active = active;
438 void SetOverlayShowGrid(boolean show_grid)
440 overlay.show_grid = show_grid;
442 SetOverlayActive(show_grid);
445 SetOverlayEnabled(TRUE);
448 boolean GetOverlayActive()
450 return overlay.active;
453 void SetDrawDeactivationMask(int draw_deactivation_mask)
455 gfx.draw_deactivation_mask = draw_deactivation_mask;
458 int GetDrawDeactivationMask()
460 return gfx.draw_deactivation_mask;
463 void SetDrawBackgroundMask(int draw_background_mask)
465 gfx.draw_background_mask = draw_background_mask;
468 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
470 if (background_bitmap_tile != NULL)
471 gfx.background_bitmap_mask |= mask;
473 gfx.background_bitmap_mask &= ~mask;
475 if (background_bitmap_tile == NULL) /* empty background requested */
478 if (mask == REDRAW_ALL)
479 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
480 0, 0, video.width, video.height);
481 else if (mask == REDRAW_FIELD)
482 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
483 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
484 else if (mask == REDRAW_DOOR_1)
485 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
486 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
489 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
491 /* remove every mask before setting mask for window */
492 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
493 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
494 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
497 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
499 /* remove window area mask before setting mask for main area */
500 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
501 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
502 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
505 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
507 /* remove window area mask before setting mask for door area */
508 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
509 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
510 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
514 /* ========================================================================= */
515 /* video functions */
516 /* ========================================================================= */
518 inline static int GetRealDepth(int depth)
520 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
523 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
524 int width, int height, Pixel color)
526 SDLFillRectangle(bitmap, x, y, width, height, color);
528 if (bitmap == backbuffer)
529 SetRedrawMaskFromArea(x, y, width, height);
532 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
533 int src_x, int src_y, int width, int height,
534 int dst_x, int dst_y, int mask_mode)
536 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
537 dst_x, dst_y, mask_mode);
539 if (dst_bitmap == backbuffer)
540 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
543 void LimitScreenUpdates(boolean enable)
545 SDLLimitScreenUpdates(enable);
548 void InitVideoDefaults(void)
550 video.default_depth = 32;
553 void InitVideoDisplay(void)
555 if (program.headless)
558 SDLInitVideoDisplay();
559 #if defined(TARGET_SDL2)
564 void CloseVideoDisplay(void)
566 KeyboardAutoRepeatOn();
568 SDL_QuitSubSystem(SDL_INIT_VIDEO);
571 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
574 video.height = height;
575 video.depth = GetRealDepth(depth);
577 video.screen_width = width;
578 video.screen_height = height;
579 video.screen_xoffset = 0;
580 video.screen_yoffset = 0;
582 video.fullscreen_available = FULLSCREEN_STATUS;
583 video.fullscreen_enabled = FALSE;
585 video.window_scaling_available = WINDOW_SCALING_STATUS;
587 video.frame_delay = 0;
588 video.frame_delay_value = GAME_FRAME_DELAY;
590 video.shifted_up = FALSE;
591 video.shifted_up_pos = 0;
592 video.shifted_up_pos_last = 0;
593 video.shifted_up_delay = 0;
594 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
596 SDLInitVideoBuffer(fullscreen);
598 video.initialized = !program.headless;
603 inline static void FreeBitmapPointers(Bitmap *bitmap)
608 SDLFreeBitmapPointers(bitmap);
610 checked_free(bitmap->source_filename);
611 bitmap->source_filename = NULL;
614 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
617 if (src_bitmap == NULL || dst_bitmap == NULL)
620 FreeBitmapPointers(dst_bitmap);
622 *dst_bitmap = *src_bitmap;
625 void FreeBitmap(Bitmap *bitmap)
630 FreeBitmapPointers(bitmap);
635 Bitmap *CreateBitmapStruct(void)
637 return checked_calloc(sizeof(Bitmap));
640 Bitmap *CreateBitmap(int width, int height, int depth)
642 Bitmap *new_bitmap = CreateBitmapStruct();
643 int real_width = MAX(1, width); /* prevent zero bitmap width */
644 int real_height = MAX(1, height); /* prevent zero bitmap height */
645 int real_depth = GetRealDepth(depth);
647 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
649 new_bitmap->width = real_width;
650 new_bitmap->height = real_height;
655 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
659 /* if new bitmap size fits into old one, no need to re-create it */
660 if (width <= (*bitmap)->width &&
661 height <= (*bitmap)->height)
664 /* else adjust size so that old and new bitmap size fit into it */
665 width = MAX(width, (*bitmap)->width);
666 height = MAX(height, (*bitmap)->height);
669 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
673 *bitmap = new_bitmap;
677 TransferBitmapPointers(new_bitmap, *bitmap);
682 void CloseWindow(DrawWindow *window)
686 void SetRedrawMaskFromArea(int x, int y, int width, int height)
690 int x2 = x + width - 1;
691 int y2 = y + height - 1;
693 if (width == 0 || height == 0)
696 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
697 redraw_mask |= REDRAW_FIELD;
698 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
699 redraw_mask |= REDRAW_DOOR_1;
700 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
701 redraw_mask |= REDRAW_DOOR_2;
702 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
703 redraw_mask |= REDRAW_DOOR_3;
705 redraw_mask = REDRAW_ALL;
708 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
711 if (draw_mask == REDRAW_NONE)
714 if (draw_mask & REDRAW_ALL)
717 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
720 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
723 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
726 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
732 boolean DrawingDeactivatedField()
734 if (program.headless)
737 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
743 boolean DrawingDeactivated(int x, int y, int width, int height)
745 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
748 boolean DrawingOnBackground(int x, int y)
750 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
751 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
754 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
755 int *width, int *height, boolean is_dest)
757 int clip_x, clip_y, clip_width, clip_height;
759 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
761 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
762 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
763 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
764 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
770 clip_width = bitmap->width;
771 clip_height = bitmap->height;
774 /* skip if rectangle completely outside bitmap */
776 if (*x + *width <= clip_x ||
777 *y + *height <= clip_y ||
778 *x >= clip_x + clip_width ||
779 *y >= clip_y + clip_height)
782 /* clip if rectangle overlaps bitmap */
786 *width -= clip_x - *x;
789 else if (*x + *width > clip_x + clip_width)
791 *width = clip_x + clip_width - *x;
796 *height -= clip_y - *y;
799 else if (*y + *height > clip_y + clip_height)
801 *height = clip_y + clip_height - *y;
807 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
808 int src_x, int src_y, int width, int height,
809 int dst_x, int dst_y)
811 int dst_x_unclipped = dst_x;
812 int dst_y_unclipped = dst_y;
814 if (program.headless)
817 if (src_bitmap == NULL || dst_bitmap == NULL)
820 if (DrawingDeactivated(dst_x, dst_y, width, height))
823 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
824 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
827 /* source x/y might need adjustment if destination x/y was clipped top/left */
828 src_x += dst_x - dst_x_unclipped;
829 src_y += dst_y - dst_y_unclipped;
831 #if defined(TARGET_SDL2)
832 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
833 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
834 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
835 but is already fixed in SVN and should therefore finally be fixed with
836 the next official SDL release, which is probably version 1.2.14.) */
837 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
839 if (src_bitmap == dst_bitmap)
841 /* needed when blitting directly to same bitmap -- should not be needed with
842 recent SDL libraries, but apparently does not work in 1.2.11 directly */
844 static Bitmap *tmp_bitmap = NULL;
845 static int tmp_bitmap_xsize = 0;
846 static int tmp_bitmap_ysize = 0;
848 /* start with largest static bitmaps for initial bitmap size ... */
849 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
851 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
852 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
855 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
856 if (src_bitmap->width > tmp_bitmap_xsize ||
857 src_bitmap->height > tmp_bitmap_ysize)
859 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
860 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
862 FreeBitmap(tmp_bitmap);
867 if (tmp_bitmap == NULL)
868 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
871 sysCopyArea(src_bitmap, tmp_bitmap,
872 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
873 sysCopyArea(tmp_bitmap, dst_bitmap,
874 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
880 sysCopyArea(src_bitmap, dst_bitmap,
881 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
884 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
885 int src_x, int src_y, int src_width, int src_height,
886 int dst_x, int dst_y, int dst_width, int dst_height)
888 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
889 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
890 int dst_xsize = dst_width;
891 int dst_ysize = dst_height;
892 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
893 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
896 for (y = 0; y < src_ysteps; y++)
898 for (x = 0; x < src_xsteps; x++)
900 int draw_x = dst_x + x * src_xsize;
901 int draw_y = dst_y + y * src_ysize;
902 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
903 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
905 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
911 void FadeRectangle(int x, int y, int width, int height,
912 int fade_mode, int fade_delay, int post_delay,
913 void (*draw_border_function)(void))
915 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
916 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
919 SDLFadeRectangle(x, y, width, height,
920 fade_mode, fade_delay, post_delay, draw_border_function);
923 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
926 if (DrawingDeactivated(x, y, width, height))
929 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
932 sysFillRectangle(bitmap, x, y, width, height, color);
935 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
937 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
940 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
941 int width, int height)
943 if (DrawingOnBackground(x, y))
944 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
946 ClearRectangle(bitmap, x, y, width, height);
949 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
950 int src_x, int src_y, int width, int height,
951 int dst_x, int dst_y)
953 if (DrawingDeactivated(dst_x, dst_y, width, height))
956 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
957 dst_x, dst_y, BLIT_MASKED);
960 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
961 int src_x, int src_y, int width, int height,
962 int dst_x, int dst_y)
964 if (DrawingOnBackground(dst_x, dst_y))
966 /* draw background */
967 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
970 /* draw foreground */
971 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
975 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
979 void BlitTexture(Bitmap *bitmap,
980 int src_x, int src_y, int width, int height,
981 int dst_x, int dst_y)
986 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
990 void BlitTextureMasked(Bitmap *bitmap,
991 int src_x, int src_y, int width, int height,
992 int dst_x, int dst_y)
997 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1001 void BlitToScreen(Bitmap *bitmap,
1002 int src_x, int src_y, int width, int height,
1003 int dst_x, int dst_y)
1008 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1009 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1010 width, height, dst_x, dst_y);
1012 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1015 void BlitToScreenMasked(Bitmap *bitmap,
1016 int src_x, int src_y, int width, int height,
1017 int dst_x, int dst_y)
1022 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1023 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1024 width, height, dst_x, dst_y);
1026 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1029 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1032 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1035 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1038 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1041 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1042 int to_x, int to_y, Pixel pixel, int line_width)
1046 if (program.headless)
1049 for (x = 0; x < line_width; x++)
1051 for (y = 0; y < line_width; y++)
1053 int dx = x - line_width / 2;
1054 int dy = y - line_width / 2;
1056 if ((x == 0 && y == 0) ||
1057 (x == 0 && y == line_width - 1) ||
1058 (x == line_width - 1 && y == 0) ||
1059 (x == line_width - 1 && y == line_width - 1))
1063 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1068 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1073 for (i = 0; i < num_points - 1; i++)
1074 DrawLine(bitmap, points[i].x, points[i].y,
1075 points[i + 1].x, points[i + 1].y, pixel, line_width);
1078 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1082 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1084 if (program.headless)
1087 if (x < 0 || x >= bitmap->width ||
1088 y < 0 || y >= bitmap->height)
1091 return SDLGetPixel(bitmap, x, y);
1094 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1095 unsigned int color_g, unsigned int color_b)
1097 if (program.headless)
1100 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1103 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1105 unsigned int color_r = (color >> 16) & 0xff;
1106 unsigned int color_g = (color >> 8) & 0xff;
1107 unsigned int color_b = (color >> 0) & 0xff;
1109 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1112 void KeyboardAutoRepeatOn(void)
1114 #if defined(TARGET_SDL2)
1115 keyrepeat_status = TRUE;
1117 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1118 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1119 SDL_EnableUNICODE(1);
1123 void KeyboardAutoRepeatOff(void)
1125 #if defined(TARGET_SDL2)
1126 keyrepeat_status = FALSE;
1128 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1129 SDL_EnableUNICODE(0);
1133 boolean SetVideoMode(boolean fullscreen)
1135 return SDLSetVideoMode(fullscreen);
1138 void SetVideoFrameDelay(unsigned int frame_delay_value)
1140 video.frame_delay_value = frame_delay_value;
1143 unsigned int GetVideoFrameDelay()
1145 return video.frame_delay_value;
1148 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1150 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1151 (!fullscreen && video.fullscreen_enabled))
1152 fullscreen = SetVideoMode(fullscreen);
1157 Bitmap *LoadImage(char *filename)
1161 new_bitmap = SDLLoadImage(filename);
1164 new_bitmap->source_filename = getStringCopy(filename);
1169 Bitmap *LoadCustomImage(char *basename)
1171 char *filename = getCustomImageFilename(basename);
1174 if (filename == NULL)
1175 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1177 if ((new_bitmap = LoadImage(filename)) == NULL)
1178 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1183 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1185 char *filename = getCustomImageFilename(basename);
1188 if (filename == NULL) /* (should never happen) */
1190 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1194 if (strEqual(filename, bitmap->source_filename))
1196 /* The old and new image are the same (have the same filename and path).
1197 This usually means that this image does not exist in this graphic set
1198 and a fallback to the existing image is done. */
1203 if ((new_bitmap = LoadImage(filename)) == NULL)
1205 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1209 if (bitmap->width != new_bitmap->width ||
1210 bitmap->height != new_bitmap->height)
1212 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1214 FreeBitmap(new_bitmap);
1218 TransferBitmapPointers(new_bitmap, bitmap);
1222 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1224 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1227 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1229 if (bitmaps[IMG_BITMAP_CUSTOM])
1231 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1233 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1236 if (gfx.game_tile_size == gfx.standard_tile_size)
1238 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1243 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1244 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1245 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1247 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1249 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1250 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1253 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1254 int tile_size, boolean create_small_bitmaps)
1256 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1257 Bitmap *tmp_bitmap_final = NULL;
1258 Bitmap *tmp_bitmap_0 = NULL;
1259 Bitmap *tmp_bitmap_1 = NULL;
1260 Bitmap *tmp_bitmap_2 = NULL;
1261 Bitmap *tmp_bitmap_4 = NULL;
1262 Bitmap *tmp_bitmap_8 = NULL;
1263 Bitmap *tmp_bitmap_16 = NULL;
1264 Bitmap *tmp_bitmap_32 = NULL;
1265 int width_final, height_final;
1266 int width_0, height_0;
1267 int width_1, height_1;
1268 int width_2, height_2;
1269 int width_4, height_4;
1270 int width_8, height_8;
1271 int width_16, height_16;
1272 int width_32, height_32;
1273 int old_width, old_height;
1276 print_timestamp_init("CreateScaledBitmaps");
1278 old_width = old_bitmap->width;
1279 old_height = old_bitmap->height;
1281 /* calculate new image dimensions for final image size */
1282 width_final = old_width * zoom_factor;
1283 height_final = old_height * zoom_factor;
1285 /* get image with final size (this might require scaling up) */
1286 /* ("final" size may result in non-standard tile size image) */
1287 if (zoom_factor != 1)
1288 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1290 tmp_bitmap_final = old_bitmap;
1292 UPDATE_BUSY_STATE();
1294 width_0 = width_1 = width_final;
1295 height_0 = height_1 = height_final;
1297 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1299 if (create_small_bitmaps)
1301 /* check if we have a non-gameplay tile size image */
1302 if (tile_size != gfx.game_tile_size)
1304 /* get image with gameplay tile size */
1305 width_0 = width_final * gfx.game_tile_size / tile_size;
1306 height_0 = height_final * gfx.game_tile_size / tile_size;
1308 if (width_0 == old_width)
1309 tmp_bitmap_0 = old_bitmap;
1310 else if (width_0 == width_final)
1311 tmp_bitmap_0 = tmp_bitmap_final;
1313 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1315 UPDATE_BUSY_STATE();
1318 /* check if we have a non-standard tile size image */
1319 if (tile_size != gfx.standard_tile_size)
1321 /* get image with standard tile size */
1322 width_1 = width_final * gfx.standard_tile_size / tile_size;
1323 height_1 = height_final * gfx.standard_tile_size / tile_size;
1325 if (width_1 == old_width)
1326 tmp_bitmap_1 = old_bitmap;
1327 else if (width_1 == width_final)
1328 tmp_bitmap_1 = tmp_bitmap_final;
1329 else if (width_1 == width_0)
1330 tmp_bitmap_1 = tmp_bitmap_0;
1332 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1334 UPDATE_BUSY_STATE();
1337 /* calculate new image dimensions for small images */
1338 width_2 = width_1 / 2;
1339 height_2 = height_1 / 2;
1340 width_4 = width_1 / 4;
1341 height_4 = height_1 / 4;
1342 width_8 = width_1 / 8;
1343 height_8 = height_1 / 8;
1344 width_16 = width_1 / 16;
1345 height_16 = height_1 / 16;
1346 width_32 = width_1 / 32;
1347 height_32 = height_1 / 32;
1349 /* get image with 1/2 of normal size (for use in the level editor) */
1350 if (width_2 == old_width)
1351 tmp_bitmap_2 = old_bitmap;
1353 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1355 UPDATE_BUSY_STATE();
1357 /* get image with 1/4 of normal size (for use in the level editor) */
1358 if (width_4 == old_width)
1359 tmp_bitmap_4 = old_bitmap;
1361 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1363 UPDATE_BUSY_STATE();
1365 /* get image with 1/8 of normal size (for use on the preview screen) */
1366 if (width_8 == old_width)
1367 tmp_bitmap_8 = old_bitmap;
1369 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1371 UPDATE_BUSY_STATE();
1373 /* get image with 1/16 of normal size (for use on the preview screen) */
1374 if (width_16 == old_width)
1375 tmp_bitmap_16 = old_bitmap;
1377 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1379 UPDATE_BUSY_STATE();
1381 /* get image with 1/32 of normal size (for use on the preview screen) */
1382 if (width_32 == old_width)
1383 tmp_bitmap_32 = old_bitmap;
1385 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1387 UPDATE_BUSY_STATE();
1389 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1390 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1391 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1392 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1393 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1394 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1396 if (width_0 != width_1)
1397 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1399 if (bitmaps[IMG_BITMAP_CUSTOM])
1400 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1402 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1404 boolean free_old_bitmap = TRUE;
1406 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1407 if (bitmaps[i] == old_bitmap)
1408 free_old_bitmap = FALSE;
1410 if (free_old_bitmap)
1411 FreeBitmap(old_bitmap);
1415 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1418 UPDATE_BUSY_STATE();
1420 print_timestamp_done("CreateScaledBitmaps");
1423 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1426 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1429 void CreateBitmapTextures(Bitmap **bitmaps)
1431 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1434 void FreeBitmapTextures(Bitmap **bitmaps)
1436 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1439 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1441 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1445 /* ------------------------------------------------------------------------- */
1446 /* mouse pointer functions */
1447 /* ------------------------------------------------------------------------- */
1449 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1451 /* XPM image definitions */
1452 static const char *cursor_image_none[] =
1454 /* width height num_colors chars_per_pixel */
1484 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1485 static const char *cursor_image_dot[] =
1487 /* width height num_colors chars_per_pixel */
1516 static const char **cursor_image_playfield = cursor_image_dot;
1518 /* some people complained about a "white dot" on the screen and thought it
1519 was a graphical error... OK, let's just remove the whole pointer :-) */
1520 static const char **cursor_image_playfield = cursor_image_none;
1523 static const int cursor_bit_order = BIT_ORDER_MSB;
1525 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1527 struct MouseCursorInfo *cursor;
1528 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1529 int header_lines = 4;
1532 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1534 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1537 for (y = 0; y < cursor->width; y++)
1539 for (x = 0; x < cursor->height; x++)
1542 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1547 cursor->data[i] = cursor->mask[i] = 0;
1550 switch (image[header_lines + y][x])
1553 cursor->data[i] |= bit_mask;
1554 cursor->mask[i] |= bit_mask;
1558 cursor->mask[i] |= bit_mask;
1567 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1572 void SetMouseCursor(int mode)
1574 static struct MouseCursorInfo *cursor_none = NULL;
1575 static struct MouseCursorInfo *cursor_playfield = NULL;
1576 struct MouseCursorInfo *cursor_new;
1578 if (cursor_none == NULL)
1579 cursor_none = get_cursor_from_image(cursor_image_none);
1581 if (cursor_playfield == NULL)
1582 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1584 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1585 mode == CURSOR_NONE ? cursor_none :
1586 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1588 SDLSetMouseCursor(cursor_new);
1590 gfx.cursor_mode = mode;
1594 /* ========================================================================= */
1595 /* audio functions */
1596 /* ========================================================================= */
1598 void OpenAudio(void)
1600 /* always start with reliable default values */
1601 audio.sound_available = FALSE;
1602 audio.music_available = FALSE;
1603 audio.loops_available = FALSE;
1605 audio.sound_enabled = FALSE;
1606 audio.sound_deactivated = FALSE;
1608 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1609 audio.mixer_pid = 0;
1610 audio.device_name = NULL;
1611 audio.device_fd = -1;
1613 audio.num_channels = 0;
1614 audio.music_channel = 0;
1615 audio.first_sound_channel = 0;
1620 void CloseAudio(void)
1624 audio.sound_enabled = FALSE;
1627 void SetAudioMode(boolean enabled)
1629 if (!audio.sound_available)
1632 audio.sound_enabled = enabled;
1636 /* ========================================================================= */
1637 /* event functions */
1638 /* ========================================================================= */
1640 boolean PendingEvent(void)
1642 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1645 void WaitEvent(Event *event)
1647 SDLWaitEvent(event);
1650 void PeekEvent(Event *event)
1652 #if defined(TARGET_SDL2)
1653 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1655 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1659 void CheckQuitEvent(void)
1661 if (SDL_QuitRequested())
1662 program.exit_function(0);
1665 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1667 #if defined(TARGET_SDL2)
1668 /* key up/down events in SDL2 do not return text characters anymore */
1669 return event->keysym.sym;
1672 #if ENABLE_UNUSED_CODE
1673 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1674 (int)event->keysym.unicode,
1675 (int)event->keysym.sym,
1676 (int)SDL_GetModState());
1679 if (with_modifiers &&
1680 event->keysym.unicode > 0x0000 &&
1681 event->keysym.unicode < 0x2000)
1682 return event->keysym.unicode;
1684 return event->keysym.sym;
1689 KeyMod HandleKeyModState(Key key, int key_status)
1691 static KeyMod current_modifiers = KMOD_None;
1693 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1695 KeyMod new_modifier = KMOD_None;
1700 new_modifier = KMOD_Shift_L;
1703 new_modifier = KMOD_Shift_R;
1705 case KSYM_Control_L:
1706 new_modifier = KMOD_Control_L;
1708 case KSYM_Control_R:
1709 new_modifier = KMOD_Control_R;
1712 new_modifier = KMOD_Meta_L;
1715 new_modifier = KMOD_Meta_R;
1718 new_modifier = KMOD_Alt_L;
1721 new_modifier = KMOD_Alt_R;
1727 if (key_status == KEY_PRESSED)
1728 current_modifiers |= new_modifier;
1730 current_modifiers &= ~new_modifier;
1733 return current_modifiers;
1736 KeyMod GetKeyModState()
1738 return (KeyMod)SDL_GetModState();
1741 KeyMod GetKeyModStateFromEvents()
1743 /* always use key modifier state as tracked from key events (this is needed
1744 if the modifier key event was injected into the event queue, but the key
1745 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1746 query the keys as held pressed on the keyboard) -- this case is currently
1747 only used to filter out clipboard insert events from "True X-Mouse" tool */
1749 return HandleKeyModState(KSYM_UNDEFINED, 0);
1752 void StartTextInput(int x, int y, int width, int height)
1754 #if defined(TARGET_SDL2)
1755 #if defined(HAS_SCREEN_KEYBOARD)
1756 SDL_StartTextInput();
1758 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1760 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1761 video.shifted_up_delay = SDL_GetTicks();
1762 video.shifted_up = TRUE;
1768 void StopTextInput()
1770 #if defined(TARGET_SDL2)
1771 #if defined(HAS_SCREEN_KEYBOARD)
1772 SDL_StopTextInput();
1774 if (video.shifted_up)
1776 video.shifted_up_pos = 0;
1777 video.shifted_up_delay = SDL_GetTicks();
1778 video.shifted_up = FALSE;
1784 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1786 if (event->type != EVENT_CLIENTMESSAGE)
1789 return TRUE; /* the only possible message here is SDL_QUIT */
1793 /* ========================================================================= */
1794 /* joystick functions */
1795 /* ========================================================================= */
1797 void InitJoysticks()
1801 #if defined(NO_JOYSTICK)
1802 return; /* joysticks generally deactivated by compile-time directive */
1805 /* always start with reliable default values */
1806 joystick.status = JOYSTICK_NOT_AVAILABLE;
1807 for (i = 0; i < MAX_PLAYERS; i++)
1808 joystick.nr[i] = -1; /* no joystick configured */
1813 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1815 return SDLReadJoystick(nr, x, y, b1, b2);
1818 boolean CheckJoystickOpened(int nr)
1820 return SDLCheckJoystickOpened(nr);
1823 void ClearJoystickState()
1825 SDLClearJoystickState();