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.headless = FALSE;
109 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
110 char *server_host, int server_port)
112 network.enabled = enabled;
113 network.connected = connected;
114 network.serveronly = serveronly;
116 network.server_host = server_host;
117 network.server_port = server_port;
119 network.server_thread = NULL;
120 network.is_server_thread = FALSE;
123 void InitRuntimeInfo()
125 #if defined(HAS_TOUCH_DEVICE)
126 runtime.uses_touch_device = TRUE;
128 runtime.uses_touch_device = FALSE;
131 runtime.api_server = setup.api_server;
134 void SetWindowTitle(void)
136 program.window_title = program.window_title_function();
141 void InitWindowTitleFunction(char *(*window_title_function)(void))
143 program.window_title_function = window_title_function;
146 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
148 program.exit_message_function = exit_message_function;
151 void InitExitFunction(void (*exit_function)(int))
153 program.exit_function = exit_function;
155 // set signal handlers to custom exit function
156 // signal(SIGINT, exit_function);
157 signal(SIGTERM, exit_function);
159 // set exit function to automatically cleanup SDL stuff after exit()
163 void InitPlatformDependentStuff(void)
165 InitEmscriptenFilesystem();
167 // this is initialized in GetOptions(), but may already be used before
168 options.verbose = TRUE;
172 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
174 if (SDL_Init(sdl_init_flags) < 0)
175 Fail("SDL_Init() failed: %s", SDL_GetError());
180 void ClosePlatformDependentStuff(void)
185 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
186 int real_sx, int real_sy,
187 int full_sxsize, int full_sysize,
188 Bitmap *field_save_buffer)
194 gfx.real_sx = real_sx;
195 gfx.real_sy = real_sy;
196 gfx.full_sxsize = full_sxsize;
197 gfx.full_sysize = full_sysize;
199 gfx.field_save_buffer = field_save_buffer;
201 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
202 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
205 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
207 gfx.game_tile_size = game_tile_size;
208 gfx.standard_tile_size = standard_tile_size;
211 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
219 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
227 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
235 void InitGfxWindowInfo(int win_xsize, int win_ysize)
237 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
239 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
241 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
243 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
248 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
251 gfx.win_xsize = win_xsize;
252 gfx.win_ysize = win_ysize;
254 gfx.background_bitmap_mask = REDRAW_NONE;
257 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
259 // currently only used by MSDOS code to alloc VRAM buffer, if available
260 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
261 gfx.scrollbuffer_width = scrollbuffer_width;
262 gfx.scrollbuffer_height = scrollbuffer_height;
265 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
267 gfx.clipping_enabled = enabled;
270 gfx.clip_width = width;
271 gfx.clip_height = height;
274 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
276 gfx.draw_busy_anim_function = draw_busy_anim_function;
279 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
281 gfx.draw_global_anim_function = draw_global_anim_function;
284 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
286 gfx.draw_global_border_function = draw_global_border_function;
289 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
291 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
294 void InitGfxCustomArtworkInfo(void)
296 gfx.override_level_graphics = FALSE;
297 gfx.override_level_sounds = FALSE;
298 gfx.override_level_music = FALSE;
300 gfx.draw_init_text = TRUE;
303 void InitGfxOtherSettings(void)
305 gfx.cursor_mode = CURSOR_DEFAULT;
306 gfx.cursor_mode_override = CURSOR_UNDEFINED;
307 gfx.cursor_mode_final = gfx.cursor_mode;
309 // prevent initially displaying custom mouse cursor in upper left corner
310 gfx.mouse_x = POS_OFFSCREEN;
311 gfx.mouse_y = POS_OFFSCREEN;
314 void InitTileCursorInfo(void)
316 tile_cursor.enabled = FALSE;
317 tile_cursor.active = FALSE;
318 tile_cursor.moving = FALSE;
320 tile_cursor.xpos = 0;
321 tile_cursor.ypos = 0;
324 tile_cursor.target_x = 0;
325 tile_cursor.target_y = 0;
330 tile_cursor.xsn_debug = FALSE;
333 void InitOverlayInfo(void)
335 overlay.enabled = FALSE;
336 overlay.active = FALSE;
338 overlay.show_grid = FALSE;
340 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
341 overlay.grid_button_action = JOY_NO_ACTION;
343 SetOverlayGridSizeAndButtons();
345 #if defined(USE_TOUCH_INPUT_OVERLAY)
346 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
347 overlay.enabled = TRUE;
351 void SetOverlayGridSizeAndButtons(void)
353 int nr = GRID_ACTIVE_NR();
356 overlay.grid_xsize = setup.touch.grid_xsize[nr];
357 overlay.grid_ysize = setup.touch.grid_ysize[nr];
359 for (x = 0; x < MAX_GRID_XSIZE; x++)
360 for (y = 0; y < MAX_GRID_YSIZE; y++)
361 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
364 void SetTileCursorEnabled(boolean enabled)
366 tile_cursor.enabled = enabled;
369 void SetTileCursorActive(boolean active)
371 tile_cursor.active = active;
374 void SetTileCursorTargetXY(int x, int y)
376 // delayed placement of tile selection cursor at target position
377 // (tile cursor will be moved to target position step by step)
379 tile_cursor.xpos = x;
380 tile_cursor.ypos = y;
381 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
382 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
384 tile_cursor.moving = TRUE;
387 void SetTileCursorXY(int x, int y)
389 // immediate placement of tile selection cursor at target position
391 SetTileCursorTargetXY(x, y);
393 tile_cursor.x = tile_cursor.target_x;
394 tile_cursor.y = tile_cursor.target_y;
396 tile_cursor.moving = FALSE;
399 void SetTileCursorSXSY(int sx, int sy)
405 void SetOverlayEnabled(boolean enabled)
407 overlay.enabled = enabled;
410 void SetOverlayActive(boolean active)
412 overlay.active = active;
415 void SetOverlayShowGrid(boolean show_grid)
417 overlay.show_grid = show_grid;
419 SetOverlayActive(show_grid);
422 SetOverlayEnabled(TRUE);
425 boolean GetOverlayEnabled(void)
427 return overlay.enabled;
430 boolean GetOverlayActive(void)
432 return overlay.active;
435 void SetDrawDeactivationMask(int draw_deactivation_mask)
437 gfx.draw_deactivation_mask = draw_deactivation_mask;
440 int GetDrawDeactivationMask(void)
442 return gfx.draw_deactivation_mask;
445 void SetDrawBackgroundMask(int draw_background_mask)
447 gfx.draw_background_mask = draw_background_mask;
450 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
452 if (background_bitmap_tile != NULL)
453 gfx.background_bitmap_mask |= mask;
455 gfx.background_bitmap_mask &= ~mask;
457 if (background_bitmap_tile == NULL) // empty background requested
460 if (mask == REDRAW_ALL)
461 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
462 0, 0, video.width, video.height);
463 else if (mask == REDRAW_FIELD)
464 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
465 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
466 else if (mask == REDRAW_DOOR_1)
467 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
468 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
471 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
473 // remove every mask before setting mask for window
474 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
475 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
476 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
479 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
481 // remove window area mask before setting mask for main area
482 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
483 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
484 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
487 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
489 // remove window area mask before setting mask for door area
490 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
491 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
492 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
496 // ============================================================================
498 // ============================================================================
500 static int GetRealDepth(int depth)
502 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
505 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
506 int width, int height, Pixel color)
508 SDLFillRectangle(bitmap, x, y, width, height, color);
510 if (bitmap == backbuffer)
511 SetRedrawMaskFromArea(x, y, width, height);
514 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
515 int src_x, int src_y, int width, int height,
516 int dst_x, int dst_y, int mask_mode)
518 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
519 dst_x, dst_y, mask_mode);
521 if (dst_bitmap == backbuffer)
522 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
525 void LimitScreenUpdates(boolean enable)
527 SDLLimitScreenUpdates(enable);
530 void InitVideoDefaults(void)
532 video.default_depth = 32;
535 void InitVideoDisplay(void)
537 if (program.headless)
540 SDLInitVideoDisplay();
544 void CloseVideoDisplay(void)
546 KeyboardAutoRepeatOn();
548 SDL_QuitSubSystem(SDL_INIT_VIDEO);
551 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
554 video.height = height;
555 video.depth = GetRealDepth(depth);
557 video.screen_width = width;
558 video.screen_height = height;
559 video.screen_xoffset = 0;
560 video.screen_yoffset = 0;
562 video.fullscreen_available = FULLSCREEN_STATUS;
563 video.fullscreen_enabled = FALSE;
565 video.window_scaling_available = WINDOW_SCALING_STATUS;
567 video.frame_counter = 0;
568 video.frame_delay = 0;
569 video.frame_delay_value = GAME_FRAME_DELAY;
571 video.shifted_up = FALSE;
572 video.shifted_up_pos = 0;
573 video.shifted_up_pos_last = 0;
574 video.shifted_up_delay = 0;
575 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
577 SDLInitVideoBuffer(fullscreen);
579 video.initialized = !program.headless;
584 static void FreeBitmapPointers(Bitmap *bitmap)
589 SDLFreeBitmapPointers(bitmap);
591 checked_free(bitmap->source_filename);
592 bitmap->source_filename = NULL;
595 static void TransferBitmapPointers(Bitmap *src_bitmap,
598 if (src_bitmap == NULL || dst_bitmap == NULL)
601 FreeBitmapPointers(dst_bitmap);
603 *dst_bitmap = *src_bitmap;
606 void FreeBitmap(Bitmap *bitmap)
611 FreeBitmapPointers(bitmap);
616 Bitmap *CreateBitmapStruct(void)
618 return checked_calloc(sizeof(Bitmap));
621 Bitmap *CreateBitmap(int width, int height, int depth)
623 Bitmap *new_bitmap = CreateBitmapStruct();
624 int real_width = MAX(1, width); // prevent zero bitmap width
625 int real_height = MAX(1, height); // prevent zero bitmap height
626 int real_depth = GetRealDepth(depth);
628 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
630 new_bitmap->width = real_width;
631 new_bitmap->height = real_height;
636 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
640 // if new bitmap size fits into old one, no need to re-create it
641 if (width <= (*bitmap)->width &&
642 height <= (*bitmap)->height)
645 // else adjust size so that old and new bitmap size fit into it
646 width = MAX(width, (*bitmap)->width);
647 height = MAX(height, (*bitmap)->height);
650 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
654 *bitmap = new_bitmap;
658 TransferBitmapPointers(new_bitmap, *bitmap);
664 static void CloseWindow(DrawWindow *window)
669 void SetRedrawMaskFromArea(int x, int y, int width, int height)
673 int x2 = x + width - 1;
674 int y2 = y + height - 1;
676 if (width == 0 || height == 0)
679 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
680 redraw_mask |= REDRAW_FIELD;
681 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
682 redraw_mask |= REDRAW_DOOR_1;
683 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
684 redraw_mask |= REDRAW_DOOR_2;
685 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
686 redraw_mask |= REDRAW_DOOR_3;
688 redraw_mask = REDRAW_ALL;
691 static boolean CheckDrawingArea(int x, int y, int width, int height,
694 if (draw_mask == REDRAW_NONE)
697 if (draw_mask & REDRAW_ALL)
700 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
703 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
706 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
709 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
715 boolean DrawingDeactivatedField(void)
717 if (program.headless)
720 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
726 boolean DrawingDeactivated(int x, int y, int width, int height)
728 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
731 boolean DrawingOnBackground(int x, int y)
733 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
734 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
737 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
738 int *width, int *height, boolean is_dest)
740 int clip_x, clip_y, clip_width, clip_height;
742 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
744 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
745 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
746 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
747 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
753 clip_width = bitmap->width;
754 clip_height = bitmap->height;
757 // skip if rectangle completely outside bitmap
759 if (*x + *width <= clip_x ||
760 *y + *height <= clip_y ||
761 *x >= clip_x + clip_width ||
762 *y >= clip_y + clip_height)
765 // clip if rectangle overlaps bitmap
769 *width -= clip_x - *x;
772 else if (*x + *width > clip_x + clip_width)
774 *width = clip_x + clip_width - *x;
779 *height -= clip_y - *y;
782 else if (*y + *height > clip_y + clip_height)
784 *height = clip_y + clip_height - *y;
790 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
791 int src_x, int src_y, int width, int height,
792 int dst_x, int dst_y)
794 int dst_x_unclipped = dst_x;
795 int dst_y_unclipped = dst_y;
797 if (program.headless)
800 if (src_bitmap == NULL || dst_bitmap == NULL)
803 if (DrawingDeactivated(dst_x, dst_y, width, height))
806 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
807 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
810 // source x/y might need adjustment if destination x/y was clipped top/left
811 src_x += dst_x - dst_x_unclipped;
812 src_y += dst_y - dst_y_unclipped;
814 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
815 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
816 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
817 but is already fixed in SVN and should therefore finally be fixed with
818 the next official SDL release, which is probably version 1.2.14.) */
819 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
821 if (src_bitmap == dst_bitmap)
823 // needed when blitting directly to same bitmap -- should not be needed with
824 // recent SDL libraries, but apparently does not work in 1.2.11 directly
826 static Bitmap *tmp_bitmap = NULL;
827 static int tmp_bitmap_xsize = 0;
828 static int tmp_bitmap_ysize = 0;
830 // start with largest static bitmaps for initial bitmap size ...
831 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
833 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
834 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
837 // ... and allow for later re-adjustments due to custom artwork bitmaps
838 if (src_bitmap->width > tmp_bitmap_xsize ||
839 src_bitmap->height > tmp_bitmap_ysize)
841 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
842 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
844 FreeBitmap(tmp_bitmap);
849 if (tmp_bitmap == NULL)
850 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
853 sysCopyArea(src_bitmap, tmp_bitmap,
854 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
855 sysCopyArea(tmp_bitmap, dst_bitmap,
856 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
861 sysCopyArea(src_bitmap, dst_bitmap,
862 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
865 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
866 int src_x, int src_y, int src_width, int src_height,
867 int dst_x, int dst_y, int dst_width, int dst_height)
869 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
870 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
871 int dst_xsize = dst_width;
872 int dst_ysize = dst_height;
873 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
874 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
877 for (y = 0; y < src_ysteps; y++)
879 for (x = 0; x < src_xsteps; x++)
881 int draw_x = dst_x + x * src_xsize;
882 int draw_y = dst_y + y * src_ysize;
883 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
884 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
886 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
892 void FadeRectangle(int x, int y, int width, int height,
893 int fade_mode, int fade_delay, int post_delay,
894 void (*draw_border_function)(void))
896 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
897 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
900 SDLFadeRectangle(x, y, width, height,
901 fade_mode, fade_delay, post_delay, draw_border_function);
904 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
907 if (DrawingDeactivated(x, y, width, height))
910 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
913 sysFillRectangle(bitmap, x, y, width, height, color);
916 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
918 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
921 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
922 int width, int height)
924 if (DrawingOnBackground(x, y))
925 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
927 ClearRectangle(bitmap, x, y, width, height);
930 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
931 int src_x, int src_y, int width, int height,
932 int dst_x, int dst_y)
934 if (DrawingDeactivated(dst_x, dst_y, width, height))
937 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
938 dst_x, dst_y, BLIT_MASKED);
941 void BlitBitmapOnBackground(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 (DrawingOnBackground(dst_x, dst_y))
948 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
952 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
956 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
960 void BlitTexture(Bitmap *bitmap,
961 int src_x, int src_y, int width, int height,
962 int dst_x, int dst_y)
967 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
971 void BlitTextureMasked(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 BlitToScreen(Bitmap *bitmap,
983 int src_x, int src_y, int width, int height,
984 int dst_x, int dst_y)
989 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
990 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
991 width, height, dst_x, dst_y);
993 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
996 void BlitToScreenMasked(Bitmap *bitmap,
997 int src_x, int src_y, int width, int height,
998 int dst_x, int dst_y)
1003 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1004 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1005 width, height, dst_x, dst_y);
1007 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1010 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1013 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1016 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1019 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1022 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1023 int to_x, int to_y, Pixel pixel, int line_width)
1027 if (program.headless)
1030 for (x = 0; x < line_width; x++)
1032 for (y = 0; y < line_width; y++)
1034 int dx = x - line_width / 2;
1035 int dy = y - line_width / 2;
1037 if ((x == 0 && y == 0) ||
1038 (x == 0 && y == line_width - 1) ||
1039 (x == line_width - 1 && y == 0) ||
1040 (x == line_width - 1 && y == line_width - 1))
1044 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1049 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1054 for (i = 0; i < num_points - 1; i++)
1055 DrawLine(bitmap, points[i].x, points[i].y,
1056 points[i + 1].x, points[i + 1].y, pixel, line_width);
1059 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1063 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1065 if (program.headless)
1068 if (x < 0 || x >= bitmap->width ||
1069 y < 0 || y >= bitmap->height)
1072 return SDLGetPixel(bitmap, x, y);
1075 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1076 unsigned int color_g, unsigned int color_b)
1078 if (program.headless)
1081 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1084 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1086 unsigned int color_r = (color >> 16) & 0xff;
1087 unsigned int color_g = (color >> 8) & 0xff;
1088 unsigned int color_b = (color >> 0) & 0xff;
1090 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1093 void KeyboardAutoRepeatOn(void)
1095 keyrepeat_status = TRUE;
1098 void KeyboardAutoRepeatOff(void)
1100 keyrepeat_status = FALSE;
1103 boolean SetVideoMode(boolean fullscreen)
1105 return SDLSetVideoMode(fullscreen);
1108 void SetVideoFrameDelay(unsigned int frame_delay_value)
1110 video.frame_delay_value = frame_delay_value;
1113 unsigned int GetVideoFrameDelay(void)
1115 return video.frame_delay_value;
1118 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1120 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1121 (!fullscreen && video.fullscreen_enabled))
1122 fullscreen = SetVideoMode(fullscreen);
1127 Bitmap *LoadImage(char *filename)
1131 new_bitmap = SDLLoadImage(filename);
1134 new_bitmap->source_filename = getStringCopy(filename);
1139 Bitmap *LoadCustomImage(char *basename)
1141 char *filename = getCustomImageFilename(basename);
1144 if (filename == NULL)
1145 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1147 if ((new_bitmap = LoadImage(filename)) == NULL)
1148 Fail("LoadImage('%s') failed", basename);
1153 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1155 char *filename = getCustomImageFilename(basename);
1158 if (filename == NULL) // (should never happen)
1160 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1165 if (strEqual(filename, bitmap->source_filename))
1167 // The old and new image are the same (have the same filename and path).
1168 // This usually means that this image does not exist in this graphic set
1169 // and a fallback to the existing image is done.
1174 if ((new_bitmap = LoadImage(filename)) == NULL)
1176 Warn("LoadImage('%s') failed", basename);
1181 if (bitmap->width != new_bitmap->width ||
1182 bitmap->height != new_bitmap->height)
1184 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1187 FreeBitmap(new_bitmap);
1192 TransferBitmapPointers(new_bitmap, bitmap);
1196 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1198 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1201 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1203 if (bitmaps[IMG_BITMAP_CUSTOM])
1205 // check if original sized bitmap points to custom sized bitmap
1206 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1208 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1210 // keep pointer of previous custom size bitmap
1211 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1213 // set original bitmap pointer to scaled original bitmap of other size
1214 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1216 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1220 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1223 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1226 if (gfx.game_tile_size == gfx.standard_tile_size)
1228 // set game bitmap pointer to standard sized bitmap (already existing)
1229 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1234 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1235 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1236 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1238 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1240 // set game bitmap pointer to custom sized bitmap (newly created)
1241 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1244 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1245 int tile_size, boolean create_small_bitmaps)
1247 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1248 Bitmap *tmp_bitmap_final = NULL;
1249 Bitmap *tmp_bitmap_0 = NULL;
1250 Bitmap *tmp_bitmap_1 = NULL;
1251 Bitmap *tmp_bitmap_2 = NULL;
1252 Bitmap *tmp_bitmap_4 = NULL;
1253 Bitmap *tmp_bitmap_8 = NULL;
1254 Bitmap *tmp_bitmap_16 = NULL;
1255 Bitmap *tmp_bitmap_32 = NULL;
1256 int width_final, height_final;
1257 int width_0, height_0;
1258 int width_1, height_1;
1259 int width_2, height_2;
1260 int width_4, height_4;
1261 int width_8, height_8;
1262 int width_16, height_16;
1263 int width_32, height_32;
1264 int old_width, old_height;
1267 print_timestamp_init("CreateScaledBitmaps");
1269 old_width = old_bitmap->width;
1270 old_height = old_bitmap->height;
1272 // calculate new image dimensions for final image size
1273 width_final = old_width * zoom_factor;
1274 height_final = old_height * zoom_factor;
1276 // get image with final size (this might require scaling up)
1277 // ("final" size may result in non-standard tile size image)
1278 if (zoom_factor != 1)
1279 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1281 tmp_bitmap_final = old_bitmap;
1283 UPDATE_BUSY_STATE();
1285 width_0 = width_1 = width_final;
1286 height_0 = height_1 = height_final;
1288 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1290 if (create_small_bitmaps)
1292 // check if we have a non-gameplay tile size image
1293 if (tile_size != gfx.game_tile_size)
1295 // get image with gameplay tile size
1296 width_0 = width_final * gfx.game_tile_size / tile_size;
1297 height_0 = height_final * gfx.game_tile_size / tile_size;
1299 if (width_0 == old_width)
1300 tmp_bitmap_0 = old_bitmap;
1301 else if (width_0 == width_final)
1302 tmp_bitmap_0 = tmp_bitmap_final;
1304 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1306 UPDATE_BUSY_STATE();
1309 // check if we have a non-standard tile size image
1310 if (tile_size != gfx.standard_tile_size)
1312 // get image with standard tile size
1313 width_1 = width_final * gfx.standard_tile_size / tile_size;
1314 height_1 = height_final * gfx.standard_tile_size / tile_size;
1316 if (width_1 == old_width)
1317 tmp_bitmap_1 = old_bitmap;
1318 else if (width_1 == width_final)
1319 tmp_bitmap_1 = tmp_bitmap_final;
1320 else if (width_1 == width_0)
1321 tmp_bitmap_1 = tmp_bitmap_0;
1323 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1325 UPDATE_BUSY_STATE();
1328 // calculate new image dimensions for small images
1329 width_2 = width_1 / 2;
1330 height_2 = height_1 / 2;
1331 width_4 = width_1 / 4;
1332 height_4 = height_1 / 4;
1333 width_8 = width_1 / 8;
1334 height_8 = height_1 / 8;
1335 width_16 = width_1 / 16;
1336 height_16 = height_1 / 16;
1337 width_32 = width_1 / 32;
1338 height_32 = height_1 / 32;
1340 // get image with 1/2 of normal size (for use in the level editor)
1341 if (width_2 == old_width)
1342 tmp_bitmap_2 = old_bitmap;
1344 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1346 UPDATE_BUSY_STATE();
1348 // get image with 1/4 of normal size (for use in the level editor)
1349 if (width_4 == old_width)
1350 tmp_bitmap_4 = old_bitmap;
1352 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1354 UPDATE_BUSY_STATE();
1356 // get image with 1/8 of normal size (for use on the preview screen)
1357 if (width_8 == old_width)
1358 tmp_bitmap_8 = old_bitmap;
1360 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1362 UPDATE_BUSY_STATE();
1364 // get image with 1/16 of normal size (for use on the preview screen)
1365 if (width_16 == old_width)
1366 tmp_bitmap_16 = old_bitmap;
1368 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1370 UPDATE_BUSY_STATE();
1372 // get image with 1/32 of normal size (for use on the preview screen)
1373 if (width_32 == old_width)
1374 tmp_bitmap_32 = old_bitmap;
1376 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1378 UPDATE_BUSY_STATE();
1380 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1381 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1382 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1383 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1384 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1385 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1387 if (width_0 != width_1)
1388 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1390 if (bitmaps[IMG_BITMAP_CUSTOM])
1391 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1393 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1395 // store the "final" (up-scaled) original bitmap, if not already stored
1397 int tmp_bitmap_final_nr = -1;
1399 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1400 if (bitmaps[i] == tmp_bitmap_final)
1401 tmp_bitmap_final_nr = i;
1403 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1405 // store pointer of scaled original bitmap (not used for any other size)
1406 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1408 // set original bitmap pointer to scaled original bitmap of other size
1409 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1413 // set original bitmap pointer to corresponding sized bitmap
1414 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1417 // free the "old" (unscaled) original bitmap, if not already stored
1419 boolean free_old_bitmap = TRUE;
1421 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1422 if (bitmaps[i] == old_bitmap)
1423 free_old_bitmap = FALSE;
1425 if (free_old_bitmap)
1427 // copy image filename from old to new standard sized bitmap
1428 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1429 getStringCopy(old_bitmap->source_filename);
1431 FreeBitmap(old_bitmap);
1436 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1438 // set original bitmap pointer to corresponding sized bitmap
1439 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1441 if (old_bitmap != tmp_bitmap_1)
1442 FreeBitmap(old_bitmap);
1445 UPDATE_BUSY_STATE();
1447 print_timestamp_done("CreateScaledBitmaps");
1450 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1453 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1456 void CreateBitmapTextures(Bitmap **bitmaps)
1458 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1459 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1461 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1464 void FreeBitmapTextures(Bitmap **bitmaps)
1466 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1467 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1469 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1472 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1474 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1478 // ----------------------------------------------------------------------------
1479 // mouse pointer functions
1480 // ----------------------------------------------------------------------------
1482 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1484 // XPM image definitions
1485 static const char *cursor_image_none[] =
1487 // width height num_colors chars_per_pixel
1517 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1518 static const char *cursor_image_dot[] =
1520 // width height num_colors chars_per_pixel
1549 static const char **cursor_image_playfield = cursor_image_dot;
1551 // some people complained about a "white dot" on the screen and thought it
1552 // was a graphical error... OK, let's just remove the whole pointer :-)
1553 static const char **cursor_image_playfield = cursor_image_none;
1556 static const int cursor_bit_order = BIT_ORDER_MSB;
1558 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1560 struct MouseCursorInfo *cursor;
1561 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1562 int header_lines = 4;
1565 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1567 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1570 for (y = 0; y < cursor->width; y++)
1572 for (x = 0; x < cursor->height; x++)
1575 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1580 cursor->data[i] = cursor->mask[i] = 0;
1583 switch (image[header_lines + y][x])
1586 cursor->data[i] |= bit_mask;
1587 cursor->mask[i] |= bit_mask;
1591 cursor->mask[i] |= bit_mask;
1600 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1605 void SetMouseCursor(int mode)
1607 static struct MouseCursorInfo *cursor_none = NULL;
1608 static struct MouseCursorInfo *cursor_playfield = NULL;
1609 struct MouseCursorInfo *cursor_new;
1610 int mode_final = mode;
1612 if (cursor_none == NULL)
1613 cursor_none = get_cursor_from_image(cursor_image_none);
1615 if (cursor_playfield == NULL)
1616 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1618 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1619 mode_final = gfx.cursor_mode_override;
1621 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1622 mode_final == CURSOR_NONE ? cursor_none :
1623 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1625 SDLSetMouseCursor(cursor_new);
1627 gfx.cursor_mode = mode;
1628 gfx.cursor_mode_final = mode_final;
1631 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1633 // mouse events do not contain logical screen size corrections yet
1634 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1636 mouse_x -= video.screen_xoffset;
1637 mouse_y -= video.screen_yoffset;
1639 gfx.mouse_x = mouse_x;
1640 gfx.mouse_y = mouse_y;
1643 void UpdateMousePosition(void)
1645 int mouse_x, mouse_y;
1648 SDL_GetMouseState(&mouse_x, &mouse_y);
1650 UpdateRawMousePosition(mouse_x, mouse_y);
1654 // ============================================================================
1656 // ============================================================================
1658 void OpenAudio(void)
1660 // always start with reliable default values
1661 audio.sound_available = FALSE;
1662 audio.music_available = FALSE;
1663 audio.loops_available = FALSE;
1665 audio.sound_enabled = FALSE;
1666 audio.sound_deactivated = FALSE;
1668 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1669 audio.mixer_pid = 0;
1670 audio.device_name = NULL;
1671 audio.device_fd = -1;
1673 audio.num_channels = 0;
1674 audio.music_channel = 0;
1675 audio.first_sound_channel = 0;
1680 void CloseAudio(void)
1684 audio.sound_enabled = FALSE;
1687 void SetAudioMode(boolean enabled)
1689 if (!audio.sound_available)
1692 audio.sound_enabled = enabled;
1696 // ============================================================================
1698 // ============================================================================
1700 void InitEventFilter(EventFilter filter_function)
1702 SDL_SetEventFilter(filter_function, NULL);
1705 boolean PendingEvent(void)
1707 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1710 void WaitEvent(Event *event)
1712 SDLWaitEvent(event);
1715 void PeekEvent(Event *event)
1717 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1720 void PumpEvents(void)
1725 void CheckQuitEvent(void)
1727 if (SDL_QuitRequested())
1728 program.exit_function(0);
1731 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1733 // key up/down events in SDL2 do not return text characters anymore
1734 return event->keysym.sym;
1737 KeyMod HandleKeyModState(Key key, int key_status)
1739 static KeyMod current_modifiers = KMOD_None;
1741 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1743 KeyMod new_modifier = KMOD_None;
1748 new_modifier = KMOD_Shift_L;
1751 new_modifier = KMOD_Shift_R;
1753 case KSYM_Control_L:
1754 new_modifier = KMOD_Control_L;
1756 case KSYM_Control_R:
1757 new_modifier = KMOD_Control_R;
1760 new_modifier = KMOD_Meta_L;
1763 new_modifier = KMOD_Meta_R;
1766 new_modifier = KMOD_Alt_L;
1769 new_modifier = KMOD_Alt_R;
1775 if (key_status == KEY_PRESSED)
1776 current_modifiers |= new_modifier;
1778 current_modifiers &= ~new_modifier;
1781 return current_modifiers;
1784 KeyMod GetKeyModState(void)
1786 return (KeyMod)SDL_GetModState();
1789 KeyMod GetKeyModStateFromEvents(void)
1791 /* always use key modifier state as tracked from key events (this is needed
1792 if the modifier key event was injected into the event queue, but the key
1793 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1794 query the keys as held pressed on the keyboard) -- this case is currently
1795 only used to filter out clipboard insert events from "True X-Mouse" tool */
1797 return HandleKeyModState(KSYM_UNDEFINED, 0);
1800 void StartTextInput(int x, int y, int width, int height)
1802 textinput_status = TRUE;
1804 #if defined(HAS_SCREEN_KEYBOARD)
1805 SDL_StartTextInput();
1807 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1809 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1810 video.shifted_up_delay = SDL_GetTicks();
1811 video.shifted_up = TRUE;
1816 void StopTextInput(void)
1818 textinput_status = FALSE;
1820 #if defined(HAS_SCREEN_KEYBOARD)
1821 SDL_StopTextInput();
1823 if (video.shifted_up)
1825 video.shifted_up_pos = 0;
1826 video.shifted_up_delay = SDL_GetTicks();
1827 video.shifted_up = FALSE;
1832 void PushUserEvent(int code, int value1, int value2)
1836 SDL_memset(&event, 0, sizeof(event));
1838 event.type = EVENT_USER;
1840 event.value1 = value1;
1841 event.value2 = value2;
1843 SDL_PushEvent((SDL_Event *)&event);
1847 // ============================================================================
1848 // joystick functions
1849 // ============================================================================
1851 void InitJoysticks(void)
1855 #if defined(NO_JOYSTICK)
1856 return; // joysticks generally deactivated by compile-time directive
1859 // always start with reliable default values
1860 joystick.status = JOYSTICK_NOT_AVAILABLE;
1861 for (i = 0; i < MAX_PLAYERS; i++)
1862 joystick.nr[i] = -1; // no joystick configured
1867 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1869 return SDLReadJoystick(nr, x, y, b1, b2);
1872 boolean CheckJoystickOpened(int nr)
1874 return SDLCheckJoystickOpened(nr);
1877 void ClearJoystickState(void)
1879 SDLClearJoystickState();
1883 // ============================================================================
1884 // Emscripten functions
1885 // ============================================================================
1887 void InitEmscriptenFilesystem(void)
1889 #if defined(PLATFORM_EMSCRIPTEN)
1892 Module.sync_done = 0;
1894 FS.mkdir('/persistent'); // create persistent data directory
1895 FS.mount(IDBFS, {}, '/persistent'); // mount with IDBFS filesystem type
1896 FS.syncfs(true, function(err) // sync persistent data into memory
1899 Module.sync_done = 1;
1903 // wait for persistent data to be synchronized to memory
1904 while (emscripten_run_script_int("Module.sync_done") == 0)
1909 void SyncEmscriptenFilesystem(void)
1911 #if defined(PLATFORM_EMSCRIPTEN)
1914 FS.syncfs(function(err)