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)(boolean))
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 (program.headless)
912 if (DrawingDeactivated(x, y, width, height))
915 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
918 sysFillRectangle(bitmap, x, y, width, height, color);
921 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
923 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
926 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
927 int width, int height)
929 if (DrawingOnBackground(x, y))
930 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
932 ClearRectangle(bitmap, x, y, width, height);
935 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
936 int src_x, int src_y, int width, int height,
937 int dst_x, int dst_y)
939 if (DrawingDeactivated(dst_x, dst_y, width, height))
942 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
943 dst_x, dst_y, BLIT_MASKED);
946 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
947 int src_x, int src_y, int width, int height,
948 int dst_x, int dst_y)
950 if (DrawingOnBackground(dst_x, dst_y))
953 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
957 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
961 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
965 void BlitTexture(Bitmap *bitmap,
966 int src_x, int src_y, int width, int height,
967 int dst_x, int dst_y)
972 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
976 void BlitTextureMasked(Bitmap *bitmap,
977 int src_x, int src_y, int width, int height,
978 int dst_x, int dst_y)
983 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
987 void BlitToScreen(Bitmap *bitmap,
988 int src_x, int src_y, int width, int height,
989 int dst_x, int dst_y)
994 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
995 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
996 width, height, dst_x, dst_y);
998 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1001 void BlitToScreenMasked(Bitmap *bitmap,
1002 int src_x, int src_y, int width, int height,
1003 int dst_x, int dst_y)
1008 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1009 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1010 width, height, dst_x, dst_y);
1012 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1015 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1018 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1021 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1024 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1027 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1028 int to_x, int to_y, Pixel pixel, int line_width)
1032 if (program.headless)
1035 for (x = 0; x < line_width; x++)
1037 for (y = 0; y < line_width; y++)
1039 int dx = x - line_width / 2;
1040 int dy = y - line_width / 2;
1042 if ((x == 0 && y == 0) ||
1043 (x == 0 && y == line_width - 1) ||
1044 (x == line_width - 1 && y == 0) ||
1045 (x == line_width - 1 && y == line_width - 1))
1049 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1054 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1059 for (i = 0; i < num_points - 1; i++)
1060 DrawLine(bitmap, points[i].x, points[i].y,
1061 points[i + 1].x, points[i + 1].y, pixel, line_width);
1064 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1068 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1070 if (program.headless)
1073 if (x < 0 || x >= bitmap->width ||
1074 y < 0 || y >= bitmap->height)
1077 return SDLGetPixel(bitmap, x, y);
1080 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1081 unsigned int color_g, unsigned int color_b)
1083 if (program.headless)
1086 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1089 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1091 unsigned int color_r = (color >> 16) & 0xff;
1092 unsigned int color_g = (color >> 8) & 0xff;
1093 unsigned int color_b = (color >> 0) & 0xff;
1095 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1098 void KeyboardAutoRepeatOn(void)
1100 keyrepeat_status = TRUE;
1103 void KeyboardAutoRepeatOff(void)
1105 keyrepeat_status = FALSE;
1108 boolean SetVideoMode(boolean fullscreen)
1110 return SDLSetVideoMode(fullscreen);
1113 void SetVideoFrameDelay(unsigned int frame_delay_value)
1115 video.frame_delay_value = frame_delay_value;
1118 unsigned int GetVideoFrameDelay(void)
1120 return video.frame_delay_value;
1123 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1125 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1126 (!fullscreen && video.fullscreen_enabled))
1127 fullscreen = SetVideoMode(fullscreen);
1132 Bitmap *LoadImage(char *filename)
1136 new_bitmap = SDLLoadImage(filename);
1139 new_bitmap->source_filename = getStringCopy(filename);
1144 Bitmap *LoadCustomImage(char *basename)
1146 char *filename = getCustomImageFilename(basename);
1149 if (filename == NULL)
1150 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1152 if ((new_bitmap = LoadImage(filename)) == NULL)
1153 Fail("LoadImage('%s') failed", basename);
1158 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1160 char *filename = getCustomImageFilename(basename);
1163 if (filename == NULL) // (should never happen)
1165 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1170 if (strEqual(filename, bitmap->source_filename))
1172 // The old and new image are the same (have the same filename and path).
1173 // This usually means that this image does not exist in this graphic set
1174 // and a fallback to the existing image is done.
1179 if ((new_bitmap = LoadImage(filename)) == NULL)
1181 Warn("LoadImage('%s') failed", basename);
1186 if (bitmap->width != new_bitmap->width ||
1187 bitmap->height != new_bitmap->height)
1189 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1192 FreeBitmap(new_bitmap);
1197 TransferBitmapPointers(new_bitmap, bitmap);
1201 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1203 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1206 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1208 if (bitmaps[IMG_BITMAP_CUSTOM])
1210 // check if original sized bitmap points to custom sized bitmap
1211 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1213 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1215 // keep pointer of previous custom size bitmap
1216 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1218 // set original bitmap pointer to scaled original bitmap of other size
1219 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1221 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1225 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1228 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1231 if (gfx.game_tile_size == gfx.standard_tile_size)
1233 // set game bitmap pointer to standard sized bitmap (already existing)
1234 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1239 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1240 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1241 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1243 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1245 // set game bitmap pointer to custom sized bitmap (newly created)
1246 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1249 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1250 int tile_size, boolean create_small_bitmaps)
1252 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1253 Bitmap *tmp_bitmap_final = NULL;
1254 Bitmap *tmp_bitmap_0 = NULL;
1255 Bitmap *tmp_bitmap_1 = NULL;
1256 Bitmap *tmp_bitmap_2 = NULL;
1257 Bitmap *tmp_bitmap_4 = NULL;
1258 Bitmap *tmp_bitmap_8 = NULL;
1259 Bitmap *tmp_bitmap_16 = NULL;
1260 Bitmap *tmp_bitmap_32 = NULL;
1261 int width_final, height_final;
1262 int width_0, height_0;
1263 int width_1, height_1;
1264 int width_2, height_2;
1265 int width_4, height_4;
1266 int width_8, height_8;
1267 int width_16, height_16;
1268 int width_32, height_32;
1269 int old_width, old_height;
1272 print_timestamp_init("CreateScaledBitmaps");
1274 old_width = old_bitmap->width;
1275 old_height = old_bitmap->height;
1277 // calculate new image dimensions for final image size
1278 width_final = old_width * zoom_factor;
1279 height_final = old_height * zoom_factor;
1281 // get image with final size (this might require scaling up)
1282 // ("final" size may result in non-standard tile size image)
1283 if (zoom_factor != 1)
1284 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1286 tmp_bitmap_final = old_bitmap;
1288 UPDATE_BUSY_STATE();
1290 width_0 = width_1 = width_final;
1291 height_0 = height_1 = height_final;
1293 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1295 if (create_small_bitmaps)
1297 // check if we have a non-gameplay tile size image
1298 if (tile_size != gfx.game_tile_size)
1300 // get image with gameplay tile size
1301 width_0 = width_final * gfx.game_tile_size / tile_size;
1302 height_0 = height_final * gfx.game_tile_size / tile_size;
1304 if (width_0 == old_width)
1305 tmp_bitmap_0 = old_bitmap;
1306 else if (width_0 == width_final)
1307 tmp_bitmap_0 = tmp_bitmap_final;
1309 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1311 UPDATE_BUSY_STATE();
1314 // check if we have a non-standard tile size image
1315 if (tile_size != gfx.standard_tile_size)
1317 // get image with standard tile size
1318 width_1 = width_final * gfx.standard_tile_size / tile_size;
1319 height_1 = height_final * gfx.standard_tile_size / tile_size;
1321 if (width_1 == old_width)
1322 tmp_bitmap_1 = old_bitmap;
1323 else if (width_1 == width_final)
1324 tmp_bitmap_1 = tmp_bitmap_final;
1325 else if (width_1 == width_0)
1326 tmp_bitmap_1 = tmp_bitmap_0;
1328 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1330 UPDATE_BUSY_STATE();
1333 // calculate new image dimensions for small images
1334 width_2 = width_1 / 2;
1335 height_2 = height_1 / 2;
1336 width_4 = width_1 / 4;
1337 height_4 = height_1 / 4;
1338 width_8 = width_1 / 8;
1339 height_8 = height_1 / 8;
1340 width_16 = width_1 / 16;
1341 height_16 = height_1 / 16;
1342 width_32 = width_1 / 32;
1343 height_32 = height_1 / 32;
1345 // get image with 1/2 of normal size (for use in the level editor)
1346 if (width_2 == old_width)
1347 tmp_bitmap_2 = old_bitmap;
1349 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1351 UPDATE_BUSY_STATE();
1353 // get image with 1/4 of normal size (for use in the level editor)
1354 if (width_4 == old_width)
1355 tmp_bitmap_4 = old_bitmap;
1357 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1359 UPDATE_BUSY_STATE();
1361 // get image with 1/8 of normal size (for use on the preview screen)
1362 if (width_8 == old_width)
1363 tmp_bitmap_8 = old_bitmap;
1365 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1367 UPDATE_BUSY_STATE();
1369 // get image with 1/16 of normal size (for use on the preview screen)
1370 if (width_16 == old_width)
1371 tmp_bitmap_16 = old_bitmap;
1373 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1375 UPDATE_BUSY_STATE();
1377 // get image with 1/32 of normal size (for use on the preview screen)
1378 if (width_32 == old_width)
1379 tmp_bitmap_32 = old_bitmap;
1381 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1383 UPDATE_BUSY_STATE();
1385 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1386 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1387 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1388 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1389 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1390 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1392 if (width_0 != width_1)
1393 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1395 if (bitmaps[IMG_BITMAP_CUSTOM])
1396 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1398 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1400 // store the "final" (up-scaled) original bitmap, if not already stored
1402 int tmp_bitmap_final_nr = -1;
1404 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1405 if (bitmaps[i] == tmp_bitmap_final)
1406 tmp_bitmap_final_nr = i;
1408 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1410 // store pointer of scaled original bitmap (not used for any other size)
1411 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1413 // set original bitmap pointer to scaled original bitmap of other size
1414 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1418 // set original bitmap pointer to corresponding sized bitmap
1419 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1422 // free the "old" (unscaled) original bitmap, if not already stored
1424 boolean free_old_bitmap = TRUE;
1426 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1427 if (bitmaps[i] == old_bitmap)
1428 free_old_bitmap = FALSE;
1430 if (free_old_bitmap)
1432 // copy image filename from old to new standard sized bitmap
1433 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1434 getStringCopy(old_bitmap->source_filename);
1436 FreeBitmap(old_bitmap);
1441 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1443 // set original bitmap pointer to corresponding sized bitmap
1444 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1446 if (old_bitmap != tmp_bitmap_1)
1447 FreeBitmap(old_bitmap);
1450 UPDATE_BUSY_STATE();
1452 print_timestamp_done("CreateScaledBitmaps");
1455 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1458 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1461 void CreateBitmapTextures(Bitmap **bitmaps)
1463 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1464 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1466 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1469 void FreeBitmapTextures(Bitmap **bitmaps)
1471 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1472 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1474 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1477 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1479 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1483 // ----------------------------------------------------------------------------
1484 // mouse pointer functions
1485 // ----------------------------------------------------------------------------
1487 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1489 // XPM image definitions
1490 static const char *cursor_image_none[] =
1492 // width height num_colors chars_per_pixel
1522 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1523 static const char *cursor_image_dot[] =
1525 // width height num_colors chars_per_pixel
1554 static const char **cursor_image_playfield = cursor_image_dot;
1556 // some people complained about a "white dot" on the screen and thought it
1557 // was a graphical error... OK, let's just remove the whole pointer :-)
1558 static const char **cursor_image_playfield = cursor_image_none;
1561 static const int cursor_bit_order = BIT_ORDER_MSB;
1563 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1565 struct MouseCursorInfo *cursor;
1566 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1567 int header_lines = 4;
1570 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1572 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1575 for (y = 0; y < cursor->width; y++)
1577 for (x = 0; x < cursor->height; x++)
1580 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1585 cursor->data[i] = cursor->mask[i] = 0;
1588 switch (image[header_lines + y][x])
1591 cursor->data[i] |= bit_mask;
1592 cursor->mask[i] |= bit_mask;
1596 cursor->mask[i] |= bit_mask;
1605 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1610 void SetMouseCursor(int mode)
1612 static struct MouseCursorInfo *cursor_none = NULL;
1613 static struct MouseCursorInfo *cursor_playfield = NULL;
1614 struct MouseCursorInfo *cursor_new;
1615 int mode_final = mode;
1617 if (cursor_none == NULL)
1618 cursor_none = get_cursor_from_image(cursor_image_none);
1620 if (cursor_playfield == NULL)
1621 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1623 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1624 mode_final = gfx.cursor_mode_override;
1626 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1627 mode_final == CURSOR_NONE ? cursor_none :
1628 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1630 SDLSetMouseCursor(cursor_new);
1632 gfx.cursor_mode = mode;
1633 gfx.cursor_mode_final = mode_final;
1636 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1638 // mouse events do not contain logical screen size corrections yet
1639 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1641 mouse_x -= video.screen_xoffset;
1642 mouse_y -= video.screen_yoffset;
1644 gfx.mouse_x = mouse_x;
1645 gfx.mouse_y = mouse_y;
1648 void UpdateMousePosition(void)
1650 int mouse_x, mouse_y;
1653 SDL_GetMouseState(&mouse_x, &mouse_y);
1655 UpdateRawMousePosition(mouse_x, mouse_y);
1659 // ============================================================================
1661 // ============================================================================
1663 void OpenAudio(void)
1665 // always start with reliable default values
1666 audio.sound_available = FALSE;
1667 audio.music_available = FALSE;
1668 audio.loops_available = FALSE;
1670 audio.sound_enabled = FALSE;
1671 audio.sound_deactivated = FALSE;
1673 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1674 audio.mixer_pid = 0;
1675 audio.device_name = NULL;
1676 audio.device_fd = -1;
1678 audio.num_channels = 0;
1679 audio.music_channel = 0;
1680 audio.first_sound_channel = 0;
1685 void CloseAudio(void)
1689 audio.sound_enabled = FALSE;
1692 void SetAudioMode(boolean enabled)
1694 if (!audio.sound_available)
1697 audio.sound_enabled = enabled;
1701 // ============================================================================
1703 // ============================================================================
1705 void InitEventFilter(EventFilter filter_function)
1707 SDL_SetEventFilter(filter_function, NULL);
1710 boolean PendingEvent(void)
1712 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1715 void WaitEvent(Event *event)
1717 SDLWaitEvent(event);
1720 void PeekEvent(Event *event)
1722 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1725 void PumpEvents(void)
1730 void CheckQuitEvent(void)
1732 if (SDL_QuitRequested())
1733 program.exit_function(0);
1736 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1738 // key up/down events in SDL2 do not return text characters anymore
1739 return event->keysym.sym;
1742 KeyMod HandleKeyModState(Key key, int key_status)
1744 static KeyMod current_modifiers = KMOD_None;
1746 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1748 KeyMod new_modifier = KMOD_None;
1753 new_modifier = KMOD_Shift_L;
1756 new_modifier = KMOD_Shift_R;
1758 case KSYM_Control_L:
1759 new_modifier = KMOD_Control_L;
1761 case KSYM_Control_R:
1762 new_modifier = KMOD_Control_R;
1765 new_modifier = KMOD_Meta_L;
1768 new_modifier = KMOD_Meta_R;
1771 new_modifier = KMOD_Alt_L;
1774 new_modifier = KMOD_Alt_R;
1780 if (key_status == KEY_PRESSED)
1781 current_modifiers |= new_modifier;
1783 current_modifiers &= ~new_modifier;
1786 return current_modifiers;
1789 KeyMod GetKeyModState(void)
1791 return (KeyMod)SDL_GetModState();
1794 KeyMod GetKeyModStateFromEvents(void)
1796 /* always use key modifier state as tracked from key events (this is needed
1797 if the modifier key event was injected into the event queue, but the key
1798 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1799 query the keys as held pressed on the keyboard) -- this case is currently
1800 only used to filter out clipboard insert events from "True X-Mouse" tool */
1802 return HandleKeyModState(KSYM_UNDEFINED, 0);
1805 void StartTextInput(int x, int y, int width, int height)
1807 textinput_status = TRUE;
1809 #if defined(HAS_SCREEN_KEYBOARD)
1810 SDL_StartTextInput();
1812 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1814 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1815 video.shifted_up_delay = SDL_GetTicks();
1816 video.shifted_up = TRUE;
1821 void StopTextInput(void)
1823 textinput_status = FALSE;
1825 #if defined(HAS_SCREEN_KEYBOARD)
1826 SDL_StopTextInput();
1828 if (video.shifted_up)
1830 video.shifted_up_pos = 0;
1831 video.shifted_up_delay = SDL_GetTicks();
1832 video.shifted_up = FALSE;
1837 void PushUserEvent(int code, int value1, int value2)
1841 SDL_memset(&event, 0, sizeof(event));
1843 event.type = EVENT_USER;
1845 event.value1 = value1;
1846 event.value2 = value2;
1848 SDL_PushEvent((SDL_Event *)&event);
1851 boolean PendingEscapeKeyEvent(void)
1857 // check if any key press event is pending
1858 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1861 // check if pressed key is "Escape" key
1862 if (event.key.keysym.sym == KSYM_Escape)
1870 // ============================================================================
1871 // joystick functions
1872 // ============================================================================
1874 void InitJoysticks(void)
1878 #if defined(NO_JOYSTICK)
1879 return; // joysticks generally deactivated by compile-time directive
1882 // always start with reliable default values
1883 joystick.status = JOYSTICK_NOT_AVAILABLE;
1884 for (i = 0; i < MAX_PLAYERS; i++)
1885 joystick.nr[i] = -1; // no joystick configured
1890 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1892 return SDLReadJoystick(nr, x, y, b1, b2);
1895 boolean CheckJoystickOpened(int nr)
1897 return SDLCheckJoystickOpened(nr);
1900 void ClearJoystickState(void)
1902 SDLClearJoystickState();
1906 // ============================================================================
1907 // Emscripten functions
1908 // ============================================================================
1910 void InitEmscriptenFilesystem(void)
1912 #if defined(PLATFORM_EMSCRIPTEN)
1915 dir = UTF8ToString($0);
1917 Module.sync_done = 0;
1919 FS.mkdir(dir); // create persistent data directory
1920 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1921 FS.syncfs(true, function(err) // sync persistent data into memory
1924 Module.sync_done = 1;
1926 }, PERSISTENT_DIRECTORY);
1928 // wait for persistent data to be synchronized to memory
1929 while (emscripten_run_script_int("Module.sync_done") == 0)
1934 void SyncEmscriptenFilesystem(void)
1936 #if defined(PLATFORM_EMSCRIPTEN)
1939 FS.syncfs(function(err)