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 min_xsize, min_ysize;
341 min_xsize = MIN(6, DEFAULT_GRID_XSIZE);
342 min_ysize = MIN(6, DEFAULT_GRID_YSIZE);
344 startx = DEFAULT_GRID_XSIZE - min_xsize;
345 starty = DEFAULT_GRID_YSIZE - min_ysize;
347 overlay.enabled = FALSE;
348 overlay.active = FALSE;
350 overlay.show_grid = FALSE;
351 overlay.show_grid_buttons = FALSE;
353 overlay.grid_xsize = DEFAULT_GRID_XSIZE;
354 overlay.grid_ysize = DEFAULT_GRID_YSIZE;
356 for (x = 0; x < MAX_GRID_XSIZE; x++)
357 for (y = 0; y < MAX_GRID_YSIZE; y++)
358 overlay.grid_button[x][y] = CHAR_GRID_BUTTON_NONE;
360 for (x = 0; x < min_xsize; x++)
361 for (y = 0; y < min_ysize; y++)
362 overlay.grid_button[x][starty + y] =
363 default_grid_button[y][0][x];
365 for (x = 0; x < min_xsize; x++)
366 for (y = 0; y < min_ysize; y++)
367 overlay.grid_button[startx + x][starty + y] =
368 default_grid_button[y][1][x];
370 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
372 #if defined(PLATFORM_ANDROID)
373 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
374 overlay.enabled = TRUE;
378 void SetTileCursorEnabled(boolean enabled)
380 tile_cursor.enabled = enabled;
383 void SetTileCursorActive(boolean active)
385 tile_cursor.active = active;
388 void SetTileCursorTargetXY(int x, int y)
390 // delayed placement of tile selection cursor at target position
391 // (tile cursor will be moved to target position step by step)
393 tile_cursor.xpos = x;
394 tile_cursor.ypos = y;
395 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
396 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
398 tile_cursor.moving = TRUE;
401 void SetTileCursorXY(int x, int y)
403 // immediate placement of tile selection cursor at target position
405 SetTileCursorTargetXY(x, y);
407 tile_cursor.x = tile_cursor.target_x;
408 tile_cursor.y = tile_cursor.target_y;
410 tile_cursor.moving = FALSE;
413 void SetTileCursorSXSY(int sx, int sy)
419 void SetOverlayEnabled(boolean enabled)
421 overlay.enabled = enabled;
424 void SetOverlayActive(boolean active)
426 overlay.active = active;
429 void SetOverlayShowGrid(boolean show_grid)
431 overlay.show_grid = show_grid;
432 overlay.show_grid_buttons = show_grid;
434 SetOverlayActive(show_grid);
437 SetOverlayEnabled(TRUE);
440 boolean GetOverlayActive()
442 return overlay.active;
445 void SetDrawDeactivationMask(int draw_deactivation_mask)
447 gfx.draw_deactivation_mask = draw_deactivation_mask;
450 int GetDrawDeactivationMask()
452 return gfx.draw_deactivation_mask;
455 void SetDrawBackgroundMask(int draw_background_mask)
457 gfx.draw_background_mask = draw_background_mask;
460 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
462 if (background_bitmap_tile != NULL)
463 gfx.background_bitmap_mask |= mask;
465 gfx.background_bitmap_mask &= ~mask;
467 if (background_bitmap_tile == NULL) /* empty background requested */
470 if (mask == REDRAW_ALL)
471 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
472 0, 0, video.width, video.height);
473 else if (mask == REDRAW_FIELD)
474 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
475 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
476 else if (mask == REDRAW_DOOR_1)
477 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
478 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
481 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
483 /* remove every mask before setting mask for window */
484 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
485 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
486 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
489 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
491 /* remove window area mask before setting mask for main area */
492 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
493 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
494 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
497 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
499 /* remove window area mask before setting mask for door area */
500 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
501 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
502 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
506 /* ========================================================================= */
507 /* video functions */
508 /* ========================================================================= */
510 inline static int GetRealDepth(int depth)
512 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
515 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
516 int width, int height, Pixel color)
518 SDLFillRectangle(bitmap, x, y, width, height, color);
520 if (bitmap == backbuffer)
521 SetRedrawMaskFromArea(x, y, width, height);
524 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
525 int src_x, int src_y, int width, int height,
526 int dst_x, int dst_y, int mask_mode)
528 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
529 dst_x, dst_y, mask_mode);
531 if (dst_bitmap == backbuffer)
532 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
535 void LimitScreenUpdates(boolean enable)
537 SDLLimitScreenUpdates(enable);
540 void InitVideoDefaults(void)
542 video.default_depth = 32;
545 void InitVideoDisplay(void)
547 if (program.headless)
550 SDLInitVideoDisplay();
551 #if defined(TARGET_SDL2)
556 void CloseVideoDisplay(void)
558 KeyboardAutoRepeatOn();
560 SDL_QuitSubSystem(SDL_INIT_VIDEO);
563 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
566 video.height = height;
567 video.depth = GetRealDepth(depth);
569 video.screen_width = width;
570 video.screen_height = height;
571 video.screen_xoffset = 0;
572 video.screen_yoffset = 0;
574 video.fullscreen_available = FULLSCREEN_STATUS;
575 video.fullscreen_enabled = FALSE;
577 video.window_scaling_available = WINDOW_SCALING_STATUS;
579 video.frame_delay = 0;
580 video.frame_delay_value = GAME_FRAME_DELAY;
582 video.shifted_up = FALSE;
583 video.shifted_up_pos = 0;
584 video.shifted_up_pos_last = 0;
585 video.shifted_up_delay = 0;
586 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
588 SDLInitVideoBuffer(fullscreen);
590 video.initialized = !program.headless;
595 inline static void FreeBitmapPointers(Bitmap *bitmap)
600 SDLFreeBitmapPointers(bitmap);
602 checked_free(bitmap->source_filename);
603 bitmap->source_filename = NULL;
606 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
609 if (src_bitmap == NULL || dst_bitmap == NULL)
612 FreeBitmapPointers(dst_bitmap);
614 *dst_bitmap = *src_bitmap;
617 void FreeBitmap(Bitmap *bitmap)
622 FreeBitmapPointers(bitmap);
627 Bitmap *CreateBitmapStruct(void)
629 return checked_calloc(sizeof(Bitmap));
632 Bitmap *CreateBitmap(int width, int height, int depth)
634 Bitmap *new_bitmap = CreateBitmapStruct();
635 int real_width = MAX(1, width); /* prevent zero bitmap width */
636 int real_height = MAX(1, height); /* prevent zero bitmap height */
637 int real_depth = GetRealDepth(depth);
639 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
641 new_bitmap->width = real_width;
642 new_bitmap->height = real_height;
647 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
651 /* if new bitmap size fits into old one, no need to re-create it */
652 if (width <= (*bitmap)->width &&
653 height <= (*bitmap)->height)
656 /* else adjust size so that old and new bitmap size fit into it */
657 width = MAX(width, (*bitmap)->width);
658 height = MAX(height, (*bitmap)->height);
661 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
665 *bitmap = new_bitmap;
669 TransferBitmapPointers(new_bitmap, *bitmap);
674 void CloseWindow(DrawWindow *window)
678 void SetRedrawMaskFromArea(int x, int y, int width, int height)
682 int x2 = x + width - 1;
683 int y2 = y + height - 1;
685 if (width == 0 || height == 0)
688 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
689 redraw_mask |= REDRAW_FIELD;
690 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
691 redraw_mask |= REDRAW_DOOR_1;
692 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
693 redraw_mask |= REDRAW_DOOR_2;
694 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
695 redraw_mask |= REDRAW_DOOR_3;
697 redraw_mask = REDRAW_ALL;
700 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
703 if (draw_mask == REDRAW_NONE)
706 if (draw_mask & REDRAW_ALL)
709 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
712 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
715 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
718 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
724 boolean DrawingDeactivatedField()
726 if (program.headless)
729 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
735 boolean DrawingDeactivated(int x, int y, int width, int height)
737 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
740 boolean DrawingOnBackground(int x, int y)
742 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
743 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
746 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
747 int *width, int *height, boolean is_dest)
749 int clip_x, clip_y, clip_width, clip_height;
751 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
753 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
754 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
755 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
756 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
762 clip_width = bitmap->width;
763 clip_height = bitmap->height;
766 /* skip if rectangle completely outside bitmap */
768 if (*x + *width <= clip_x ||
769 *y + *height <= clip_y ||
770 *x >= clip_x + clip_width ||
771 *y >= clip_y + clip_height)
774 /* clip if rectangle overlaps bitmap */
778 *width -= clip_x - *x;
781 else if (*x + *width > clip_x + clip_width)
783 *width = clip_x + clip_width - *x;
788 *height -= clip_y - *y;
791 else if (*y + *height > clip_y + clip_height)
793 *height = clip_y + clip_height - *y;
799 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
800 int src_x, int src_y, int width, int height,
801 int dst_x, int dst_y)
803 int dst_x_unclipped = dst_x;
804 int dst_y_unclipped = dst_y;
806 if (program.headless)
809 if (src_bitmap == NULL || dst_bitmap == NULL)
812 if (DrawingDeactivated(dst_x, dst_y, width, height))
815 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
816 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
819 /* source x/y might need adjustment if destination x/y was clipped top/left */
820 src_x += dst_x - dst_x_unclipped;
821 src_y += dst_y - dst_y_unclipped;
823 #if defined(TARGET_SDL2)
824 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
825 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
826 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
827 but is already fixed in SVN and should therefore finally be fixed with
828 the next official SDL release, which is probably version 1.2.14.) */
829 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
831 if (src_bitmap == dst_bitmap)
833 /* needed when blitting directly to same bitmap -- should not be needed with
834 recent SDL libraries, but apparently does not work in 1.2.11 directly */
836 static Bitmap *tmp_bitmap = NULL;
837 static int tmp_bitmap_xsize = 0;
838 static int tmp_bitmap_ysize = 0;
840 /* start with largest static bitmaps for initial bitmap size ... */
841 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
843 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
844 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
847 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
848 if (src_bitmap->width > tmp_bitmap_xsize ||
849 src_bitmap->height > tmp_bitmap_ysize)
851 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
852 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
854 FreeBitmap(tmp_bitmap);
859 if (tmp_bitmap == NULL)
860 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
863 sysCopyArea(src_bitmap, tmp_bitmap,
864 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
865 sysCopyArea(tmp_bitmap, dst_bitmap,
866 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
872 sysCopyArea(src_bitmap, dst_bitmap,
873 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
876 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
877 int src_x, int src_y, int src_width, int src_height,
878 int dst_x, int dst_y, int dst_width, int dst_height)
880 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
881 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
882 int dst_xsize = dst_width;
883 int dst_ysize = dst_height;
884 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
885 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
888 for (y = 0; y < src_ysteps; y++)
890 for (x = 0; x < src_xsteps; x++)
892 int draw_x = dst_x + x * src_xsize;
893 int draw_y = dst_y + y * src_ysize;
894 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
895 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
897 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
903 void FadeRectangle(int x, int y, int width, int height,
904 int fade_mode, int fade_delay, int post_delay,
905 void (*draw_border_function)(void))
907 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
908 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
911 SDLFadeRectangle(x, y, width, height,
912 fade_mode, fade_delay, post_delay, draw_border_function);
915 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
918 if (DrawingDeactivated(x, y, width, height))
921 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
924 sysFillRectangle(bitmap, x, y, width, height, color);
927 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
929 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
932 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
933 int width, int height)
935 if (DrawingOnBackground(x, y))
936 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
938 ClearRectangle(bitmap, x, y, width, height);
941 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
942 int src_x, int src_y, int width, int height,
943 int dst_x, int dst_y)
945 if (DrawingDeactivated(dst_x, dst_y, width, height))
948 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
949 dst_x, dst_y, BLIT_MASKED);
952 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
953 int src_x, int src_y, int width, int height,
954 int dst_x, int dst_y)
956 if (DrawingOnBackground(dst_x, dst_y))
958 /* draw background */
959 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
962 /* draw foreground */
963 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
967 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
971 void BlitTexture(Bitmap *bitmap,
972 int src_x, int src_y, int width, int height,
973 int dst_x, int dst_y)
978 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
982 void BlitTextureMasked(Bitmap *bitmap,
983 int src_x, int src_y, int width, int height,
984 int dst_x, int dst_y)
989 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
993 void BlitToScreen(Bitmap *bitmap,
994 int src_x, int src_y, int width, int height,
995 int dst_x, int dst_y)
1000 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1001 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1002 width, height, dst_x, dst_y);
1004 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1007 void BlitToScreenMasked(Bitmap *bitmap,
1008 int src_x, int src_y, int width, int height,
1009 int dst_x, int dst_y)
1014 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1015 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1016 width, height, dst_x, dst_y);
1018 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1021 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1024 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1027 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1030 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1033 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1034 int to_x, int to_y, Pixel pixel, int line_width)
1038 if (program.headless)
1041 for (x = 0; x < line_width; x++)
1043 for (y = 0; y < line_width; y++)
1045 int dx = x - line_width / 2;
1046 int dy = y - line_width / 2;
1048 if ((x == 0 && y == 0) ||
1049 (x == 0 && y == line_width - 1) ||
1050 (x == line_width - 1 && y == 0) ||
1051 (x == line_width - 1 && y == line_width - 1))
1055 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1060 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1065 for (i = 0; i < num_points - 1; i++)
1066 DrawLine(bitmap, points[i].x, points[i].y,
1067 points[i + 1].x, points[i + 1].y, pixel, line_width);
1070 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1074 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1076 if (program.headless)
1079 if (x < 0 || x >= bitmap->width ||
1080 y < 0 || y >= bitmap->height)
1083 return SDLGetPixel(bitmap, x, y);
1086 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1087 unsigned int color_g, unsigned int color_b)
1089 if (program.headless)
1092 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1095 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1097 unsigned int color_r = (color >> 16) & 0xff;
1098 unsigned int color_g = (color >> 8) & 0xff;
1099 unsigned int color_b = (color >> 0) & 0xff;
1101 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1104 void KeyboardAutoRepeatOn(void)
1106 #if defined(TARGET_SDL2)
1107 keyrepeat_status = TRUE;
1109 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1110 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1111 SDL_EnableUNICODE(1);
1115 void KeyboardAutoRepeatOff(void)
1117 #if defined(TARGET_SDL2)
1118 keyrepeat_status = FALSE;
1120 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1121 SDL_EnableUNICODE(0);
1125 boolean SetVideoMode(boolean fullscreen)
1127 return SDLSetVideoMode(fullscreen);
1130 void SetVideoFrameDelay(unsigned int frame_delay_value)
1132 video.frame_delay_value = frame_delay_value;
1135 unsigned int GetVideoFrameDelay()
1137 return video.frame_delay_value;
1140 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1142 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1143 (!fullscreen && video.fullscreen_enabled))
1144 fullscreen = SetVideoMode(fullscreen);
1149 Bitmap *LoadImage(char *filename)
1153 new_bitmap = SDLLoadImage(filename);
1156 new_bitmap->source_filename = getStringCopy(filename);
1161 Bitmap *LoadCustomImage(char *basename)
1163 char *filename = getCustomImageFilename(basename);
1166 if (filename == NULL)
1167 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1169 if ((new_bitmap = LoadImage(filename)) == NULL)
1170 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1175 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1177 char *filename = getCustomImageFilename(basename);
1180 if (filename == NULL) /* (should never happen) */
1182 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1186 if (strEqual(filename, bitmap->source_filename))
1188 /* The old and new image are the same (have the same filename and path).
1189 This usually means that this image does not exist in this graphic set
1190 and a fallback to the existing image is done. */
1195 if ((new_bitmap = LoadImage(filename)) == NULL)
1197 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1201 if (bitmap->width != new_bitmap->width ||
1202 bitmap->height != new_bitmap->height)
1204 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1206 FreeBitmap(new_bitmap);
1210 TransferBitmapPointers(new_bitmap, bitmap);
1214 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1216 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1219 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1221 if (bitmaps[IMG_BITMAP_CUSTOM])
1223 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1225 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1228 if (gfx.game_tile_size == gfx.standard_tile_size)
1230 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1235 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1236 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1237 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1239 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1241 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1242 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1245 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1246 int tile_size, boolean create_small_bitmaps)
1248 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1249 Bitmap *tmp_bitmap_final = NULL;
1250 Bitmap *tmp_bitmap_0 = NULL;
1251 Bitmap *tmp_bitmap_1 = NULL;
1252 Bitmap *tmp_bitmap_2 = NULL;
1253 Bitmap *tmp_bitmap_4 = NULL;
1254 Bitmap *tmp_bitmap_8 = NULL;
1255 Bitmap *tmp_bitmap_16 = NULL;
1256 Bitmap *tmp_bitmap_32 = NULL;
1257 int width_final, height_final;
1258 int width_0, height_0;
1259 int width_1, height_1;
1260 int width_2, height_2;
1261 int width_4, height_4;
1262 int width_8, height_8;
1263 int width_16, height_16;
1264 int width_32, height_32;
1265 int old_width, old_height;
1268 print_timestamp_init("CreateScaledBitmaps");
1270 old_width = old_bitmap->width;
1271 old_height = old_bitmap->height;
1273 /* calculate new image dimensions for final image size */
1274 width_final = old_width * zoom_factor;
1275 height_final = old_height * zoom_factor;
1277 /* get image with final size (this might require scaling up) */
1278 /* ("final" size may result in non-standard tile size image) */
1279 if (zoom_factor != 1)
1280 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1282 tmp_bitmap_final = old_bitmap;
1284 UPDATE_BUSY_STATE();
1286 width_0 = width_1 = width_final;
1287 height_0 = height_1 = height_final;
1289 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1291 if (create_small_bitmaps)
1293 /* check if we have a non-gameplay tile size image */
1294 if (tile_size != gfx.game_tile_size)
1296 /* get image with gameplay tile size */
1297 width_0 = width_final * gfx.game_tile_size / tile_size;
1298 height_0 = height_final * gfx.game_tile_size / tile_size;
1300 if (width_0 == old_width)
1301 tmp_bitmap_0 = old_bitmap;
1302 else if (width_0 == width_final)
1303 tmp_bitmap_0 = tmp_bitmap_final;
1305 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1307 UPDATE_BUSY_STATE();
1310 /* check if we have a non-standard tile size image */
1311 if (tile_size != gfx.standard_tile_size)
1313 /* get image with standard tile size */
1314 width_1 = width_final * gfx.standard_tile_size / tile_size;
1315 height_1 = height_final * gfx.standard_tile_size / tile_size;
1317 if (width_1 == old_width)
1318 tmp_bitmap_1 = old_bitmap;
1319 else if (width_1 == width_final)
1320 tmp_bitmap_1 = tmp_bitmap_final;
1321 else if (width_1 == width_0)
1322 tmp_bitmap_1 = tmp_bitmap_0;
1324 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1326 UPDATE_BUSY_STATE();
1329 /* calculate new image dimensions for small images */
1330 width_2 = width_1 / 2;
1331 height_2 = height_1 / 2;
1332 width_4 = width_1 / 4;
1333 height_4 = height_1 / 4;
1334 width_8 = width_1 / 8;
1335 height_8 = height_1 / 8;
1336 width_16 = width_1 / 16;
1337 height_16 = height_1 / 16;
1338 width_32 = width_1 / 32;
1339 height_32 = height_1 / 32;
1341 /* get image with 1/2 of normal size (for use in the level editor) */
1342 if (width_2 == old_width)
1343 tmp_bitmap_2 = old_bitmap;
1345 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1347 UPDATE_BUSY_STATE();
1349 /* get image with 1/4 of normal size (for use in the level editor) */
1350 if (width_4 == old_width)
1351 tmp_bitmap_4 = old_bitmap;
1353 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1355 UPDATE_BUSY_STATE();
1357 /* get image with 1/8 of normal size (for use on the preview screen) */
1358 if (width_8 == old_width)
1359 tmp_bitmap_8 = old_bitmap;
1361 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1363 UPDATE_BUSY_STATE();
1365 /* get image with 1/16 of normal size (for use on the preview screen) */
1366 if (width_16 == old_width)
1367 tmp_bitmap_16 = old_bitmap;
1369 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1371 UPDATE_BUSY_STATE();
1373 /* get image with 1/32 of normal size (for use on the preview screen) */
1374 if (width_32 == old_width)
1375 tmp_bitmap_32 = old_bitmap;
1377 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1379 UPDATE_BUSY_STATE();
1381 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1382 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1383 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1384 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1385 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1386 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1388 if (width_0 != width_1)
1389 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1391 if (bitmaps[IMG_BITMAP_CUSTOM])
1392 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1394 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1396 boolean free_old_bitmap = TRUE;
1398 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1399 if (bitmaps[i] == old_bitmap)
1400 free_old_bitmap = FALSE;
1402 if (free_old_bitmap)
1403 FreeBitmap(old_bitmap);
1407 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1410 UPDATE_BUSY_STATE();
1412 print_timestamp_done("CreateScaledBitmaps");
1415 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1418 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1421 void CreateBitmapTextures(Bitmap **bitmaps)
1423 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1426 void FreeBitmapTextures(Bitmap **bitmaps)
1428 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1431 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1433 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1437 /* ------------------------------------------------------------------------- */
1438 /* mouse pointer functions */
1439 /* ------------------------------------------------------------------------- */
1441 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1443 /* XPM image definitions */
1444 static const char *cursor_image_none[] =
1446 /* width height num_colors chars_per_pixel */
1476 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1477 static const char *cursor_image_dot[] =
1479 /* width height num_colors chars_per_pixel */
1508 static const char **cursor_image_playfield = cursor_image_dot;
1510 /* some people complained about a "white dot" on the screen and thought it
1511 was a graphical error... OK, let's just remove the whole pointer :-) */
1512 static const char **cursor_image_playfield = cursor_image_none;
1515 static const int cursor_bit_order = BIT_ORDER_MSB;
1517 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1519 struct MouseCursorInfo *cursor;
1520 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1521 int header_lines = 4;
1524 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1526 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1529 for (y = 0; y < cursor->width; y++)
1531 for (x = 0; x < cursor->height; x++)
1534 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1539 cursor->data[i] = cursor->mask[i] = 0;
1542 switch (image[header_lines + y][x])
1545 cursor->data[i] |= bit_mask;
1546 cursor->mask[i] |= bit_mask;
1550 cursor->mask[i] |= bit_mask;
1559 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1564 void SetMouseCursor(int mode)
1566 static struct MouseCursorInfo *cursor_none = NULL;
1567 static struct MouseCursorInfo *cursor_playfield = NULL;
1568 struct MouseCursorInfo *cursor_new;
1570 if (cursor_none == NULL)
1571 cursor_none = get_cursor_from_image(cursor_image_none);
1573 if (cursor_playfield == NULL)
1574 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1576 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1577 mode == CURSOR_NONE ? cursor_none :
1578 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1580 SDLSetMouseCursor(cursor_new);
1582 gfx.cursor_mode = mode;
1586 /* ========================================================================= */
1587 /* audio functions */
1588 /* ========================================================================= */
1590 void OpenAudio(void)
1592 /* always start with reliable default values */
1593 audio.sound_available = FALSE;
1594 audio.music_available = FALSE;
1595 audio.loops_available = FALSE;
1597 audio.sound_enabled = FALSE;
1598 audio.sound_deactivated = FALSE;
1600 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1601 audio.mixer_pid = 0;
1602 audio.device_name = NULL;
1603 audio.device_fd = -1;
1605 audio.num_channels = 0;
1606 audio.music_channel = 0;
1607 audio.first_sound_channel = 0;
1612 void CloseAudio(void)
1616 audio.sound_enabled = FALSE;
1619 void SetAudioMode(boolean enabled)
1621 if (!audio.sound_available)
1624 audio.sound_enabled = enabled;
1628 /* ========================================================================= */
1629 /* event functions */
1630 /* ========================================================================= */
1632 boolean PendingEvent(void)
1634 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1637 void WaitEvent(Event *event)
1639 SDLWaitEvent(event);
1642 void PeekEvent(Event *event)
1644 #if defined(TARGET_SDL2)
1645 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1647 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1651 void CheckQuitEvent(void)
1653 if (SDL_QuitRequested())
1654 program.exit_function(0);
1657 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1659 #if defined(TARGET_SDL2)
1660 /* key up/down events in SDL2 do not return text characters anymore */
1661 return event->keysym.sym;
1664 #if ENABLE_UNUSED_CODE
1665 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1666 (int)event->keysym.unicode,
1667 (int)event->keysym.sym,
1668 (int)SDL_GetModState());
1671 if (with_modifiers &&
1672 event->keysym.unicode > 0x0000 &&
1673 event->keysym.unicode < 0x2000)
1674 return event->keysym.unicode;
1676 return event->keysym.sym;
1681 KeyMod HandleKeyModState(Key key, int key_status)
1683 static KeyMod current_modifiers = KMOD_None;
1685 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1687 KeyMod new_modifier = KMOD_None;
1692 new_modifier = KMOD_Shift_L;
1695 new_modifier = KMOD_Shift_R;
1697 case KSYM_Control_L:
1698 new_modifier = KMOD_Control_L;
1700 case KSYM_Control_R:
1701 new_modifier = KMOD_Control_R;
1704 new_modifier = KMOD_Meta_L;
1707 new_modifier = KMOD_Meta_R;
1710 new_modifier = KMOD_Alt_L;
1713 new_modifier = KMOD_Alt_R;
1719 if (key_status == KEY_PRESSED)
1720 current_modifiers |= new_modifier;
1722 current_modifiers &= ~new_modifier;
1725 return current_modifiers;
1728 KeyMod GetKeyModState()
1730 return (KeyMod)SDL_GetModState();
1733 KeyMod GetKeyModStateFromEvents()
1735 /* always use key modifier state as tracked from key events (this is needed
1736 if the modifier key event was injected into the event queue, but the key
1737 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1738 query the keys as held pressed on the keyboard) -- this case is currently
1739 only used to filter out clipboard insert events from "True X-Mouse" tool */
1741 return HandleKeyModState(KSYM_UNDEFINED, 0);
1744 void StartTextInput(int x, int y, int width, int height)
1746 #if defined(TARGET_SDL2)
1747 #if defined(HAS_SCREEN_KEYBOARD)
1748 SDL_StartTextInput();
1750 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1752 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1753 video.shifted_up_delay = SDL_GetTicks();
1754 video.shifted_up = TRUE;
1760 void StopTextInput()
1762 #if defined(TARGET_SDL2)
1763 #if defined(HAS_SCREEN_KEYBOARD)
1764 SDL_StopTextInput();
1766 if (video.shifted_up)
1768 video.shifted_up_pos = 0;
1769 video.shifted_up_delay = SDL_GetTicks();
1770 video.shifted_up = FALSE;
1776 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1778 if (event->type != EVENT_CLIENTMESSAGE)
1781 return TRUE; /* the only possible message here is SDL_QUIT */
1785 /* ========================================================================= */
1786 /* joystick functions */
1787 /* ========================================================================= */
1789 void InitJoysticks()
1793 #if defined(NO_JOYSTICK)
1794 return; /* joysticks generally deactivated by compile-time directive */
1797 /* always start with reliable default values */
1798 joystick.status = JOYSTICK_NOT_AVAILABLE;
1799 for (i = 0; i < MAX_PLAYERS; i++)
1800 joystick.nr[i] = -1; /* no joystick configured */
1805 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1807 return SDLReadJoystick(nr, x, y, b1, b2);
1810 boolean CheckJoystickOpened(int nr)
1812 return SDLCheckJoystickOpened(nr);
1815 void ClearJoystickState()
1817 SDLClearJoystickState();