1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct RuntimeInfo runtime;
34 struct OptionInfo options;
35 struct VideoSystemInfo video;
36 struct AudioSystemInfo audio;
38 struct TileCursorInfo tile_cursor;
39 struct OverlayInfo overlay;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
45 LevelDirTree *leveldir_first_all = NULL;
46 LevelDirTree *leveldir_first = NULL;
47 LevelDirTree *leveldir_current = NULL;
50 struct LevelSetInfo levelset;
51 struct LevelStats level_stats[MAX_LEVELS];
53 DrawWindow *window = NULL;
54 DrawBuffer *backbuffer = NULL;
55 DrawBuffer *drawto = NULL;
57 int button_status = MB_NOT_PRESSED;
58 boolean motion_status = FALSE;
59 int wheel_steps = DEFAULT_WHEEL_STEPS;
60 boolean keyrepeat_status = TRUE;
61 boolean textinput_status = FALSE;
63 int redraw_mask = REDRAW_NONE;
68 // ============================================================================
69 // init/close functions
70 // ============================================================================
72 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
73 char *program_title, char *icon_title,
74 char *icon_filename, char *cookie_prefix,
75 char *program_version_string, int program_version)
77 program.command_basepath = getBasePath(argv0);
78 program.command_basename = getBaseName(argv0);
80 program.config_filename = config_filename;
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_path = getMainUserGameDataDir();
85 program.program_title = program_title;
86 program.window_title = "(undefined)";
87 program.icon_title = icon_title;
89 program.icon_filename = icon_filename;
91 program.cookie_prefix = cookie_prefix;
93 program.version_super = VERSION_SUPER(program_version);
94 program.version_major = VERSION_MAJOR(program_version);
95 program.version_minor = VERSION_MINOR(program_version);
96 program.version_patch = VERSION_PATCH(program_version);
97 program.version_ident = program_version;
99 program.version_string = program_version_string;
101 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
102 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
103 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
104 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
106 program.api_thread_count = 0;
108 program.headless = FALSE;
111 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
112 char *server_host, int server_port)
114 network.enabled = enabled;
115 network.connected = connected;
116 network.serveronly = serveronly;
118 network.server_host = server_host;
119 network.server_port = server_port;
121 network.server_thread = NULL;
122 network.is_server_thread = FALSE;
125 void InitRuntimeInfo()
127 #if defined(HAS_TOUCH_DEVICE)
128 runtime.uses_touch_device = TRUE;
130 runtime.uses_touch_device = FALSE;
133 runtime.use_api_server = setup.use_api_server;
136 void SetWindowTitle(void)
138 program.window_title = program.window_title_function();
143 void InitWindowTitleFunction(char *(*window_title_function)(void))
145 program.window_title_function = window_title_function;
148 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
150 program.exit_message_function = exit_message_function;
153 void InitExitFunction(void (*exit_function)(int))
155 program.exit_function = exit_function;
157 // set signal handlers to custom exit function
158 // signal(SIGINT, exit_function);
159 signal(SIGTERM, exit_function);
161 // set exit function to automatically cleanup SDL stuff after exit()
165 void InitPlatformDependentStuff(void)
167 InitEmscriptenFilesystem();
169 // this is initialized in GetOptions(), but may already be used before
170 options.verbose = TRUE;
174 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
176 if (SDL_Init(sdl_init_flags) < 0)
177 Fail("SDL_Init() failed: %s", SDL_GetError());
182 void ClosePlatformDependentStuff(void)
187 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
188 int real_sx, int real_sy,
189 int full_sxsize, int full_sysize,
190 Bitmap *field_save_buffer)
196 gfx.real_sx = real_sx;
197 gfx.real_sy = real_sy;
198 gfx.full_sxsize = full_sxsize;
199 gfx.full_sysize = full_sysize;
201 gfx.field_save_buffer = field_save_buffer;
203 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
204 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
207 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
209 gfx.game_tile_size = game_tile_size;
210 gfx.standard_tile_size = standard_tile_size;
213 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
221 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
229 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
237 void InitGfxWindowInfo(int win_xsize, int win_ysize)
239 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
241 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
243 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
248 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
250 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
253 gfx.win_xsize = win_xsize;
254 gfx.win_ysize = win_ysize;
256 gfx.background_bitmap_mask = REDRAW_NONE;
259 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
261 // currently only used by MSDOS code to alloc VRAM buffer, if available
262 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
263 gfx.scrollbuffer_width = scrollbuffer_width;
264 gfx.scrollbuffer_height = scrollbuffer_height;
267 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
269 gfx.clipping_enabled = enabled;
272 gfx.clip_width = width;
273 gfx.clip_height = height;
276 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
278 gfx.draw_busy_anim_function = draw_busy_anim_function;
281 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
283 gfx.draw_global_anim_function = draw_global_anim_function;
286 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
288 gfx.draw_global_border_function = draw_global_border_function;
291 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
293 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
296 void InitGfxCustomArtworkInfo(void)
298 gfx.override_level_graphics = FALSE;
299 gfx.override_level_sounds = FALSE;
300 gfx.override_level_music = FALSE;
302 gfx.draw_init_text = TRUE;
305 void InitGfxOtherSettings(void)
307 gfx.cursor_mode = CURSOR_DEFAULT;
308 gfx.cursor_mode_override = CURSOR_UNDEFINED;
309 gfx.cursor_mode_final = gfx.cursor_mode;
311 // prevent initially displaying custom mouse cursor in upper left corner
312 gfx.mouse_x = POS_OFFSCREEN;
313 gfx.mouse_y = POS_OFFSCREEN;
316 void InitTileCursorInfo(void)
318 tile_cursor.enabled = FALSE;
319 tile_cursor.active = FALSE;
320 tile_cursor.moving = FALSE;
322 tile_cursor.xpos = 0;
323 tile_cursor.ypos = 0;
326 tile_cursor.target_x = 0;
327 tile_cursor.target_y = 0;
332 tile_cursor.xsn_debug = FALSE;
335 void InitOverlayInfo(void)
337 overlay.enabled = FALSE;
338 overlay.active = FALSE;
340 overlay.show_grid = FALSE;
342 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
343 overlay.grid_button_action = JOY_NO_ACTION;
345 SetOverlayGridSizeAndButtons();
347 #if defined(USE_TOUCH_INPUT_OVERLAY)
348 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
349 overlay.enabled = TRUE;
353 void SetOverlayGridSizeAndButtons(void)
355 int nr = GRID_ACTIVE_NR();
358 overlay.grid_xsize = setup.touch.grid_xsize[nr];
359 overlay.grid_ysize = setup.touch.grid_ysize[nr];
361 for (x = 0; x < MAX_GRID_XSIZE; x++)
362 for (y = 0; y < MAX_GRID_YSIZE; y++)
363 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
366 void SetTileCursorEnabled(boolean enabled)
368 tile_cursor.enabled = enabled;
371 void SetTileCursorActive(boolean active)
373 tile_cursor.active = active;
376 void SetTileCursorTargetXY(int x, int y)
378 // delayed placement of tile selection cursor at target position
379 // (tile cursor will be moved to target position step by step)
381 tile_cursor.xpos = x;
382 tile_cursor.ypos = y;
383 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
384 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
386 tile_cursor.moving = TRUE;
389 void SetTileCursorXY(int x, int y)
391 // immediate placement of tile selection cursor at target position
393 SetTileCursorTargetXY(x, y);
395 tile_cursor.x = tile_cursor.target_x;
396 tile_cursor.y = tile_cursor.target_y;
398 tile_cursor.moving = FALSE;
401 void SetTileCursorSXSY(int sx, int sy)
407 void SetOverlayEnabled(boolean enabled)
409 overlay.enabled = enabled;
412 void SetOverlayActive(boolean active)
414 overlay.active = active;
417 void SetOverlayShowGrid(boolean show_grid)
419 overlay.show_grid = show_grid;
421 SetOverlayActive(show_grid);
424 SetOverlayEnabled(TRUE);
427 boolean GetOverlayEnabled(void)
429 return overlay.enabled;
432 boolean GetOverlayActive(void)
434 return overlay.active;
437 void SetDrawDeactivationMask(int draw_deactivation_mask)
439 gfx.draw_deactivation_mask = draw_deactivation_mask;
442 int GetDrawDeactivationMask(void)
444 return gfx.draw_deactivation_mask;
447 void SetDrawBackgroundMask(int draw_background_mask)
449 gfx.draw_background_mask = draw_background_mask;
452 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
454 if (background_bitmap_tile != NULL)
455 gfx.background_bitmap_mask |= mask;
457 gfx.background_bitmap_mask &= ~mask;
459 if (background_bitmap_tile == NULL) // empty background requested
462 if (mask == REDRAW_ALL)
463 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
464 0, 0, video.width, video.height);
465 else if (mask == REDRAW_FIELD)
466 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
467 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
468 else if (mask == REDRAW_DOOR_1)
469 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
470 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
473 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
475 // remove every mask before setting mask for window
476 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
477 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
478 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
481 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
483 // remove window area mask before setting mask for main area
484 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
485 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
486 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
489 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
491 // remove window area mask before setting mask for door area
492 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
493 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
494 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
498 // ============================================================================
500 // ============================================================================
502 static int GetRealDepth(int depth)
504 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
507 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
508 int width, int height, Pixel color)
510 SDLFillRectangle(bitmap, x, y, width, height, color);
512 if (bitmap == backbuffer)
513 SetRedrawMaskFromArea(x, y, width, height);
516 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
517 int src_x, int src_y, int width, int height,
518 int dst_x, int dst_y, int mask_mode)
520 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
521 dst_x, dst_y, mask_mode);
523 if (dst_bitmap == backbuffer)
524 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
527 void LimitScreenUpdates(boolean enable)
529 SDLLimitScreenUpdates(enable);
532 void InitVideoDefaults(void)
534 video.default_depth = 32;
537 void InitVideoDisplay(void)
539 if (program.headless)
542 SDLInitVideoDisplay();
546 void CloseVideoDisplay(void)
548 KeyboardAutoRepeatOn();
550 SDL_QuitSubSystem(SDL_INIT_VIDEO);
553 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
556 video.height = height;
557 video.depth = GetRealDepth(depth);
559 video.screen_width = width;
560 video.screen_height = height;
561 video.screen_xoffset = 0;
562 video.screen_yoffset = 0;
564 video.fullscreen_available = FULLSCREEN_STATUS;
565 video.fullscreen_enabled = FALSE;
567 video.window_scaling_available = WINDOW_SCALING_STATUS;
569 video.frame_counter = 0;
570 video.frame_delay = 0;
571 video.frame_delay_value = GAME_FRAME_DELAY;
573 video.shifted_up = FALSE;
574 video.shifted_up_pos = 0;
575 video.shifted_up_pos_last = 0;
576 video.shifted_up_delay = 0;
577 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
579 SDLInitVideoBuffer(fullscreen);
581 video.initialized = !program.headless;
586 static void FreeBitmapPointers(Bitmap *bitmap)
591 SDLFreeBitmapPointers(bitmap);
593 checked_free(bitmap->source_filename);
594 bitmap->source_filename = NULL;
597 static void TransferBitmapPointers(Bitmap *src_bitmap,
600 if (src_bitmap == NULL || dst_bitmap == NULL)
603 FreeBitmapPointers(dst_bitmap);
605 *dst_bitmap = *src_bitmap;
608 void FreeBitmap(Bitmap *bitmap)
613 FreeBitmapPointers(bitmap);
618 Bitmap *CreateBitmapStruct(void)
620 return checked_calloc(sizeof(Bitmap));
623 Bitmap *CreateBitmap(int width, int height, int depth)
625 Bitmap *new_bitmap = CreateBitmapStruct();
626 int real_width = MAX(1, width); // prevent zero bitmap width
627 int real_height = MAX(1, height); // prevent zero bitmap height
628 int real_depth = GetRealDepth(depth);
630 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
632 new_bitmap->width = real_width;
633 new_bitmap->height = real_height;
638 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
642 // if new bitmap size fits into old one, no need to re-create it
643 if (width <= (*bitmap)->width &&
644 height <= (*bitmap)->height)
647 // else adjust size so that old and new bitmap size fit into it
648 width = MAX(width, (*bitmap)->width);
649 height = MAX(height, (*bitmap)->height);
652 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
656 *bitmap = new_bitmap;
660 TransferBitmapPointers(new_bitmap, *bitmap);
666 static void CloseWindow(DrawWindow *window)
671 void SetRedrawMaskFromArea(int x, int y, int width, int height)
675 int x2 = x + width - 1;
676 int y2 = y + height - 1;
678 if (width == 0 || height == 0)
681 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
682 redraw_mask |= REDRAW_FIELD;
683 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
684 redraw_mask |= REDRAW_DOOR_1;
685 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
686 redraw_mask |= REDRAW_DOOR_2;
687 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
688 redraw_mask |= REDRAW_DOOR_3;
690 redraw_mask = REDRAW_ALL;
693 static boolean CheckDrawingArea(int x, int y, int width, int height,
696 if (draw_mask == REDRAW_NONE)
699 if (draw_mask & REDRAW_ALL)
702 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
705 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
708 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
711 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
717 boolean DrawingDeactivatedField(void)
719 if (program.headless)
722 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
728 boolean DrawingDeactivated(int x, int y, int width, int height)
730 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
733 boolean DrawingOnBackground(int x, int y)
735 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
736 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
739 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
740 int *width, int *height, boolean is_dest)
742 int clip_x, clip_y, clip_width, clip_height;
744 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
746 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
747 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
748 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
749 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
755 clip_width = bitmap->width;
756 clip_height = bitmap->height;
759 // skip if rectangle completely outside bitmap
761 if (*x + *width <= clip_x ||
762 *y + *height <= clip_y ||
763 *x >= clip_x + clip_width ||
764 *y >= clip_y + clip_height)
767 // clip if rectangle overlaps bitmap
771 *width -= clip_x - *x;
774 else if (*x + *width > clip_x + clip_width)
776 *width = clip_x + clip_width - *x;
781 *height -= clip_y - *y;
784 else if (*y + *height > clip_y + clip_height)
786 *height = clip_y + clip_height - *y;
792 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
793 int src_x, int src_y, int width, int height,
794 int dst_x, int dst_y)
796 int dst_x_unclipped = dst_x;
797 int dst_y_unclipped = dst_y;
799 if (program.headless)
802 if (src_bitmap == NULL || dst_bitmap == NULL)
805 if (DrawingDeactivated(dst_x, dst_y, width, height))
808 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
809 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
812 // source x/y might need adjustment if destination x/y was clipped top/left
813 src_x += dst_x - dst_x_unclipped;
814 src_y += dst_y - dst_y_unclipped;
816 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
817 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
818 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
819 but is already fixed in SVN and should therefore finally be fixed with
820 the next official SDL release, which is probably version 1.2.14.) */
821 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
823 if (src_bitmap == dst_bitmap)
825 // needed when blitting directly to same bitmap -- should not be needed with
826 // recent SDL libraries, but apparently does not work in 1.2.11 directly
828 static Bitmap *tmp_bitmap = NULL;
829 static int tmp_bitmap_xsize = 0;
830 static int tmp_bitmap_ysize = 0;
832 // start with largest static bitmaps for initial bitmap size ...
833 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
835 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
836 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
839 // ... and allow for later re-adjustments due to custom artwork bitmaps
840 if (src_bitmap->width > tmp_bitmap_xsize ||
841 src_bitmap->height > tmp_bitmap_ysize)
843 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
844 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
846 FreeBitmap(tmp_bitmap);
851 if (tmp_bitmap == NULL)
852 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
855 sysCopyArea(src_bitmap, tmp_bitmap,
856 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
857 sysCopyArea(tmp_bitmap, dst_bitmap,
858 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
863 sysCopyArea(src_bitmap, dst_bitmap,
864 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
867 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
868 int src_x, int src_y, int src_width, int src_height,
869 int dst_x, int dst_y, int dst_width, int dst_height)
871 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
872 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
873 int dst_xsize = dst_width;
874 int dst_ysize = dst_height;
875 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
876 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
879 for (y = 0; y < src_ysteps; y++)
881 for (x = 0; x < src_xsteps; x++)
883 int draw_x = dst_x + x * src_xsize;
884 int draw_y = dst_y + y * src_ysize;
885 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
886 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
888 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
894 void FadeRectangle(int x, int y, int width, int height,
895 int fade_mode, int fade_delay, int post_delay,
896 void (*draw_border_function)(void))
898 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
899 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
902 SDLFadeRectangle(x, y, width, height,
903 fade_mode, fade_delay, post_delay, draw_border_function);
906 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
909 if (DrawingDeactivated(x, y, width, height))
912 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
915 sysFillRectangle(bitmap, x, y, width, height, color);
918 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
920 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
923 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
924 int width, int height)
926 if (DrawingOnBackground(x, y))
927 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
929 ClearRectangle(bitmap, x, y, width, height);
932 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
933 int src_x, int src_y, int width, int height,
934 int dst_x, int dst_y)
936 if (DrawingDeactivated(dst_x, dst_y, width, height))
939 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
940 dst_x, dst_y, BLIT_MASKED);
943 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
944 int src_x, int src_y, int width, int height,
945 int dst_x, int dst_y)
947 if (DrawingOnBackground(dst_x, dst_y))
950 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
954 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
958 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
962 void BlitTexture(Bitmap *bitmap,
963 int src_x, int src_y, int width, int height,
964 int dst_x, int dst_y)
969 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
973 void BlitTextureMasked(Bitmap *bitmap,
974 int src_x, int src_y, int width, int height,
975 int dst_x, int dst_y)
980 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
984 void BlitToScreen(Bitmap *bitmap,
985 int src_x, int src_y, int width, int height,
986 int dst_x, int dst_y)
991 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
992 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
993 width, height, dst_x, dst_y);
995 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
998 void BlitToScreenMasked(Bitmap *bitmap,
999 int src_x, int src_y, int width, int height,
1000 int dst_x, int dst_y)
1005 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1006 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1007 width, height, dst_x, dst_y);
1009 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1012 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1015 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1018 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1021 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1024 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1025 int to_x, int to_y, Pixel pixel, int line_width)
1029 if (program.headless)
1032 for (x = 0; x < line_width; x++)
1034 for (y = 0; y < line_width; y++)
1036 int dx = x - line_width / 2;
1037 int dy = y - line_width / 2;
1039 if ((x == 0 && y == 0) ||
1040 (x == 0 && y == line_width - 1) ||
1041 (x == line_width - 1 && y == 0) ||
1042 (x == line_width - 1 && y == line_width - 1))
1046 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1051 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1056 for (i = 0; i < num_points - 1; i++)
1057 DrawLine(bitmap, points[i].x, points[i].y,
1058 points[i + 1].x, points[i + 1].y, pixel, line_width);
1061 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1065 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1067 if (program.headless)
1070 if (x < 0 || x >= bitmap->width ||
1071 y < 0 || y >= bitmap->height)
1074 return SDLGetPixel(bitmap, x, y);
1077 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1078 unsigned int color_g, unsigned int color_b)
1080 if (program.headless)
1083 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1086 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1088 unsigned int color_r = (color >> 16) & 0xff;
1089 unsigned int color_g = (color >> 8) & 0xff;
1090 unsigned int color_b = (color >> 0) & 0xff;
1092 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1095 void KeyboardAutoRepeatOn(void)
1097 keyrepeat_status = TRUE;
1100 void KeyboardAutoRepeatOff(void)
1102 keyrepeat_status = FALSE;
1105 boolean SetVideoMode(boolean fullscreen)
1107 return SDLSetVideoMode(fullscreen);
1110 void SetVideoFrameDelay(unsigned int frame_delay_value)
1112 video.frame_delay_value = frame_delay_value;
1115 unsigned int GetVideoFrameDelay(void)
1117 return video.frame_delay_value;
1120 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1122 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1123 (!fullscreen && video.fullscreen_enabled))
1124 fullscreen = SetVideoMode(fullscreen);
1129 Bitmap *LoadImage(char *filename)
1133 new_bitmap = SDLLoadImage(filename);
1136 new_bitmap->source_filename = getStringCopy(filename);
1141 Bitmap *LoadCustomImage(char *basename)
1143 char *filename = getCustomImageFilename(basename);
1146 if (filename == NULL)
1147 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1149 if ((new_bitmap = LoadImage(filename)) == NULL)
1150 Fail("LoadImage('%s') failed", basename);
1155 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1157 char *filename = getCustomImageFilename(basename);
1160 if (filename == NULL) // (should never happen)
1162 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1167 if (strEqual(filename, bitmap->source_filename))
1169 // The old and new image are the same (have the same filename and path).
1170 // This usually means that this image does not exist in this graphic set
1171 // and a fallback to the existing image is done.
1176 if ((new_bitmap = LoadImage(filename)) == NULL)
1178 Warn("LoadImage('%s') failed", basename);
1183 if (bitmap->width != new_bitmap->width ||
1184 bitmap->height != new_bitmap->height)
1186 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1189 FreeBitmap(new_bitmap);
1194 TransferBitmapPointers(new_bitmap, bitmap);
1198 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1200 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1203 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1205 if (bitmaps[IMG_BITMAP_CUSTOM])
1207 // check if original sized bitmap points to custom sized bitmap
1208 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1210 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1212 // keep pointer of previous custom size bitmap
1213 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1215 // set original bitmap pointer to scaled original bitmap of other size
1216 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1218 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1222 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1225 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1228 if (gfx.game_tile_size == gfx.standard_tile_size)
1230 // set game bitmap pointer to standard sized bitmap (already existing)
1231 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1236 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1237 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1238 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1240 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1242 // set game bitmap pointer to custom sized bitmap (newly created)
1243 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1246 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1247 int tile_size, boolean create_small_bitmaps)
1249 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1250 Bitmap *tmp_bitmap_final = NULL;
1251 Bitmap *tmp_bitmap_0 = NULL;
1252 Bitmap *tmp_bitmap_1 = NULL;
1253 Bitmap *tmp_bitmap_2 = NULL;
1254 Bitmap *tmp_bitmap_4 = NULL;
1255 Bitmap *tmp_bitmap_8 = NULL;
1256 Bitmap *tmp_bitmap_16 = NULL;
1257 Bitmap *tmp_bitmap_32 = NULL;
1258 int width_final, height_final;
1259 int width_0, height_0;
1260 int width_1, height_1;
1261 int width_2, height_2;
1262 int width_4, height_4;
1263 int width_8, height_8;
1264 int width_16, height_16;
1265 int width_32, height_32;
1266 int old_width, old_height;
1269 print_timestamp_init("CreateScaledBitmaps");
1271 old_width = old_bitmap->width;
1272 old_height = old_bitmap->height;
1274 // calculate new image dimensions for final image size
1275 width_final = old_width * zoom_factor;
1276 height_final = old_height * zoom_factor;
1278 // get image with final size (this might require scaling up)
1279 // ("final" size may result in non-standard tile size image)
1280 if (zoom_factor != 1)
1281 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1283 tmp_bitmap_final = old_bitmap;
1285 UPDATE_BUSY_STATE();
1287 width_0 = width_1 = width_final;
1288 height_0 = height_1 = height_final;
1290 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1292 if (create_small_bitmaps)
1294 // check if we have a non-gameplay tile size image
1295 if (tile_size != gfx.game_tile_size)
1297 // get image with gameplay tile size
1298 width_0 = width_final * gfx.game_tile_size / tile_size;
1299 height_0 = height_final * gfx.game_tile_size / tile_size;
1301 if (width_0 == old_width)
1302 tmp_bitmap_0 = old_bitmap;
1303 else if (width_0 == width_final)
1304 tmp_bitmap_0 = tmp_bitmap_final;
1306 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1308 UPDATE_BUSY_STATE();
1311 // check if we have a non-standard tile size image
1312 if (tile_size != gfx.standard_tile_size)
1314 // get image with standard tile size
1315 width_1 = width_final * gfx.standard_tile_size / tile_size;
1316 height_1 = height_final * gfx.standard_tile_size / tile_size;
1318 if (width_1 == old_width)
1319 tmp_bitmap_1 = old_bitmap;
1320 else if (width_1 == width_final)
1321 tmp_bitmap_1 = tmp_bitmap_final;
1322 else if (width_1 == width_0)
1323 tmp_bitmap_1 = tmp_bitmap_0;
1325 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1327 UPDATE_BUSY_STATE();
1330 // calculate new image dimensions for small images
1331 width_2 = width_1 / 2;
1332 height_2 = height_1 / 2;
1333 width_4 = width_1 / 4;
1334 height_4 = height_1 / 4;
1335 width_8 = width_1 / 8;
1336 height_8 = height_1 / 8;
1337 width_16 = width_1 / 16;
1338 height_16 = height_1 / 16;
1339 width_32 = width_1 / 32;
1340 height_32 = height_1 / 32;
1342 // get image with 1/2 of normal size (for use in the level editor)
1343 if (width_2 == old_width)
1344 tmp_bitmap_2 = old_bitmap;
1346 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1348 UPDATE_BUSY_STATE();
1350 // get image with 1/4 of normal size (for use in the level editor)
1351 if (width_4 == old_width)
1352 tmp_bitmap_4 = old_bitmap;
1354 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1356 UPDATE_BUSY_STATE();
1358 // get image with 1/8 of normal size (for use on the preview screen)
1359 if (width_8 == old_width)
1360 tmp_bitmap_8 = old_bitmap;
1362 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1364 UPDATE_BUSY_STATE();
1366 // get image with 1/16 of normal size (for use on the preview screen)
1367 if (width_16 == old_width)
1368 tmp_bitmap_16 = old_bitmap;
1370 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1372 UPDATE_BUSY_STATE();
1374 // get image with 1/32 of normal size (for use on the preview screen)
1375 if (width_32 == old_width)
1376 tmp_bitmap_32 = old_bitmap;
1378 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1380 UPDATE_BUSY_STATE();
1382 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1383 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1384 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1385 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1386 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1387 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1389 if (width_0 != width_1)
1390 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1392 if (bitmaps[IMG_BITMAP_CUSTOM])
1393 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1395 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1397 // store the "final" (up-scaled) original bitmap, if not already stored
1399 int tmp_bitmap_final_nr = -1;
1401 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1402 if (bitmaps[i] == tmp_bitmap_final)
1403 tmp_bitmap_final_nr = i;
1405 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1407 // store pointer of scaled original bitmap (not used for any other size)
1408 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1410 // set original bitmap pointer to scaled original bitmap of other size
1411 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1415 // set original bitmap pointer to corresponding sized bitmap
1416 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1419 // free the "old" (unscaled) original bitmap, if not already stored
1421 boolean free_old_bitmap = TRUE;
1423 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1424 if (bitmaps[i] == old_bitmap)
1425 free_old_bitmap = FALSE;
1427 if (free_old_bitmap)
1429 // copy image filename from old to new standard sized bitmap
1430 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1431 getStringCopy(old_bitmap->source_filename);
1433 FreeBitmap(old_bitmap);
1438 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1440 // set original bitmap pointer to corresponding sized bitmap
1441 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1443 if (old_bitmap != tmp_bitmap_1)
1444 FreeBitmap(old_bitmap);
1447 UPDATE_BUSY_STATE();
1449 print_timestamp_done("CreateScaledBitmaps");
1452 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1455 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1458 void CreateBitmapTextures(Bitmap **bitmaps)
1460 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1461 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1463 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1466 void FreeBitmapTextures(Bitmap **bitmaps)
1468 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1469 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1471 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1474 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1476 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1480 // ----------------------------------------------------------------------------
1481 // mouse pointer functions
1482 // ----------------------------------------------------------------------------
1484 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1486 // XPM image definitions
1487 static const char *cursor_image_none[] =
1489 // width height num_colors chars_per_pixel
1519 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1520 static const char *cursor_image_dot[] =
1522 // width height num_colors chars_per_pixel
1551 static const char **cursor_image_playfield = cursor_image_dot;
1553 // some people complained about a "white dot" on the screen and thought it
1554 // was a graphical error... OK, let's just remove the whole pointer :-)
1555 static const char **cursor_image_playfield = cursor_image_none;
1558 static const int cursor_bit_order = BIT_ORDER_MSB;
1560 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1562 struct MouseCursorInfo *cursor;
1563 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1564 int header_lines = 4;
1567 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1569 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1572 for (y = 0; y < cursor->width; y++)
1574 for (x = 0; x < cursor->height; x++)
1577 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1582 cursor->data[i] = cursor->mask[i] = 0;
1585 switch (image[header_lines + y][x])
1588 cursor->data[i] |= bit_mask;
1589 cursor->mask[i] |= bit_mask;
1593 cursor->mask[i] |= bit_mask;
1602 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1607 void SetMouseCursor(int mode)
1609 static struct MouseCursorInfo *cursor_none = NULL;
1610 static struct MouseCursorInfo *cursor_playfield = NULL;
1611 struct MouseCursorInfo *cursor_new;
1612 int mode_final = mode;
1614 if (cursor_none == NULL)
1615 cursor_none = get_cursor_from_image(cursor_image_none);
1617 if (cursor_playfield == NULL)
1618 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1620 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1621 mode_final = gfx.cursor_mode_override;
1623 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1624 mode_final == CURSOR_NONE ? cursor_none :
1625 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1627 SDLSetMouseCursor(cursor_new);
1629 gfx.cursor_mode = mode;
1630 gfx.cursor_mode_final = mode_final;
1633 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1635 // mouse events do not contain logical screen size corrections yet
1636 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1638 mouse_x -= video.screen_xoffset;
1639 mouse_y -= video.screen_yoffset;
1641 gfx.mouse_x = mouse_x;
1642 gfx.mouse_y = mouse_y;
1645 void UpdateMousePosition(void)
1647 int mouse_x, mouse_y;
1650 SDL_GetMouseState(&mouse_x, &mouse_y);
1652 UpdateRawMousePosition(mouse_x, mouse_y);
1656 // ============================================================================
1658 // ============================================================================
1660 void OpenAudio(void)
1662 // always start with reliable default values
1663 audio.sound_available = FALSE;
1664 audio.music_available = FALSE;
1665 audio.loops_available = FALSE;
1667 audio.sound_enabled = FALSE;
1668 audio.sound_deactivated = FALSE;
1670 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1671 audio.mixer_pid = 0;
1672 audio.device_name = NULL;
1673 audio.device_fd = -1;
1675 audio.num_channels = 0;
1676 audio.music_channel = 0;
1677 audio.first_sound_channel = 0;
1682 void CloseAudio(void)
1686 audio.sound_enabled = FALSE;
1689 void SetAudioMode(boolean enabled)
1691 if (!audio.sound_available)
1694 audio.sound_enabled = enabled;
1698 // ============================================================================
1700 // ============================================================================
1702 void InitEventFilter(EventFilter filter_function)
1704 SDL_SetEventFilter(filter_function, NULL);
1707 boolean PendingEvent(void)
1709 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1712 void WaitEvent(Event *event)
1714 SDLWaitEvent(event);
1717 void PeekEvent(Event *event)
1719 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1722 void PumpEvents(void)
1727 void CheckQuitEvent(void)
1729 if (SDL_QuitRequested())
1730 program.exit_function(0);
1733 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1735 // key up/down events in SDL2 do not return text characters anymore
1736 return event->keysym.sym;
1739 KeyMod HandleKeyModState(Key key, int key_status)
1741 static KeyMod current_modifiers = KMOD_None;
1743 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1745 KeyMod new_modifier = KMOD_None;
1750 new_modifier = KMOD_Shift_L;
1753 new_modifier = KMOD_Shift_R;
1755 case KSYM_Control_L:
1756 new_modifier = KMOD_Control_L;
1758 case KSYM_Control_R:
1759 new_modifier = KMOD_Control_R;
1762 new_modifier = KMOD_Meta_L;
1765 new_modifier = KMOD_Meta_R;
1768 new_modifier = KMOD_Alt_L;
1771 new_modifier = KMOD_Alt_R;
1777 if (key_status == KEY_PRESSED)
1778 current_modifiers |= new_modifier;
1780 current_modifiers &= ~new_modifier;
1783 return current_modifiers;
1786 KeyMod GetKeyModState(void)
1788 return (KeyMod)SDL_GetModState();
1791 KeyMod GetKeyModStateFromEvents(void)
1793 /* always use key modifier state as tracked from key events (this is needed
1794 if the modifier key event was injected into the event queue, but the key
1795 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1796 query the keys as held pressed on the keyboard) -- this case is currently
1797 only used to filter out clipboard insert events from "True X-Mouse" tool */
1799 return HandleKeyModState(KSYM_UNDEFINED, 0);
1802 void StartTextInput(int x, int y, int width, int height)
1804 textinput_status = TRUE;
1806 #if defined(HAS_SCREEN_KEYBOARD)
1807 SDL_StartTextInput();
1809 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1811 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1812 video.shifted_up_delay = SDL_GetTicks();
1813 video.shifted_up = TRUE;
1818 void StopTextInput(void)
1820 textinput_status = FALSE;
1822 #if defined(HAS_SCREEN_KEYBOARD)
1823 SDL_StopTextInput();
1825 if (video.shifted_up)
1827 video.shifted_up_pos = 0;
1828 video.shifted_up_delay = SDL_GetTicks();
1829 video.shifted_up = FALSE;
1834 void PushUserEvent(int code, int value1, int value2)
1838 SDL_memset(&event, 0, sizeof(event));
1840 event.type = EVENT_USER;
1842 event.value1 = value1;
1843 event.value2 = value2;
1845 SDL_PushEvent((SDL_Event *)&event);
1849 // ============================================================================
1850 // joystick functions
1851 // ============================================================================
1853 void InitJoysticks(void)
1857 #if defined(NO_JOYSTICK)
1858 return; // joysticks generally deactivated by compile-time directive
1861 // always start with reliable default values
1862 joystick.status = JOYSTICK_NOT_AVAILABLE;
1863 for (i = 0; i < MAX_PLAYERS; i++)
1864 joystick.nr[i] = -1; // no joystick configured
1869 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1871 return SDLReadJoystick(nr, x, y, b1, b2);
1874 boolean CheckJoystickOpened(int nr)
1876 return SDLCheckJoystickOpened(nr);
1879 void ClearJoystickState(void)
1881 SDLClearJoystickState();
1885 // ============================================================================
1886 // Emscripten functions
1887 // ============================================================================
1889 void InitEmscriptenFilesystem(void)
1891 #if defined(PLATFORM_EMSCRIPTEN)
1894 Module.sync_done = 0;
1896 FS.mkdir('/persistent'); // create persistent data directory
1897 FS.mount(IDBFS, {}, '/persistent'); // mount with IDBFS filesystem type
1898 FS.syncfs(true, function(err) // sync persistent data into memory
1901 Module.sync_done = 1;
1905 // wait for persistent data to be synchronized to memory
1906 while (emscripten_run_script_int("Module.sync_done") == 0)
1911 void SyncEmscriptenFilesystem(void)
1913 #if defined(PLATFORM_EMSCRIPTEN)
1916 FS.syncfs(function(err)