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 *command_filename,
73 char *config_filename, char *userdata_subdir,
74 char *program_basename, char *program_title,
75 char *icon_filename, char *cookie_prefix,
76 char *program_version_string, int program_version)
78 program.command_basepath = getBasePath(command_filename);
79 program.command_basename = getBaseName(command_filename);
81 program.config_filename = config_filename;
83 program.userdata_subdir = userdata_subdir;
84 program.userdata_path = getMainUserGameDataDir();
86 program.program_basename = program_basename;
87 program.program_title = program_title;
88 program.window_title = "(undefined)";
90 program.icon_filename = icon_filename;
92 program.cookie_prefix = cookie_prefix;
94 program.version_super = VERSION_SUPER(program_version);
95 program.version_major = VERSION_MAJOR(program_version);
96 program.version_minor = VERSION_MINOR(program_version);
97 program.version_patch = VERSION_PATCH(program_version);
98 program.version_ident = program_version;
100 program.version_string = program_version_string;
102 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
103 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
104 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
105 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
107 program.api_thread_count = 0;
109 program.headless = FALSE;
112 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
113 char *server_host, int server_port)
115 network.enabled = enabled;
116 network.connected = connected;
117 network.serveronly = serveronly;
119 network.server_host = server_host;
120 network.server_port = server_port;
122 network.server_thread = NULL;
123 network.is_server_thread = FALSE;
126 void InitRuntimeInfo()
128 #if defined(HAS_TOUCH_DEVICE)
129 runtime.uses_touch_device = TRUE;
131 runtime.uses_touch_device = FALSE;
134 runtime.use_api_server = setup.use_api_server;
137 void SetWindowTitle(void)
139 program.window_title = program.window_title_function();
144 void InitWindowTitleFunction(char *(*window_title_function)(void))
146 program.window_title_function = window_title_function;
149 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
151 program.exit_message_function = exit_message_function;
154 void InitExitFunction(void (*exit_function)(int))
156 program.exit_function = exit_function;
158 // set signal handlers to custom exit function
159 // signal(SIGINT, exit_function);
160 signal(SIGTERM, exit_function);
162 // set exit function to automatically cleanup SDL stuff after exit()
166 void InitPlatformDependentStuff(void)
168 InitEmscriptenFilesystem();
170 // this is initialized in GetOptions(), but may already be used before
171 options.verbose = TRUE;
175 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
177 if (SDL_Init(sdl_init_flags) < 0)
178 Fail("SDL_Init() failed: %s", SDL_GetError());
183 void ClosePlatformDependentStuff(void)
188 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
189 int real_sx, int real_sy,
190 int full_sxsize, int full_sysize,
191 Bitmap *field_save_buffer)
197 gfx.real_sx = real_sx;
198 gfx.real_sy = real_sy;
199 gfx.full_sxsize = full_sxsize;
200 gfx.full_sysize = full_sysize;
202 gfx.field_save_buffer = field_save_buffer;
204 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
205 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
208 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
210 gfx.game_tile_size = game_tile_size;
211 gfx.standard_tile_size = standard_tile_size;
214 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
222 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
230 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
238 void InitGfxWindowInfo(int win_xsize, int win_ysize)
240 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
242 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
248 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
249 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
251 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
254 gfx.win_xsize = win_xsize;
255 gfx.win_ysize = win_ysize;
257 gfx.background_bitmap_mask = REDRAW_NONE;
260 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
262 // currently only used by MSDOS code to alloc VRAM buffer, if available
263 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
264 gfx.scrollbuffer_width = scrollbuffer_width;
265 gfx.scrollbuffer_height = scrollbuffer_height;
268 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
270 gfx.clipping_enabled = enabled;
273 gfx.clip_width = width;
274 gfx.clip_height = height;
277 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean))
279 gfx.draw_busy_anim_function = draw_busy_anim_function;
282 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
284 gfx.draw_global_anim_function = draw_global_anim_function;
287 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
289 gfx.draw_global_border_function = draw_global_border_function;
292 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
294 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
297 void InitGfxCustomArtworkInfo(void)
299 gfx.override_level_graphics = FALSE;
300 gfx.override_level_sounds = FALSE;
301 gfx.override_level_music = FALSE;
303 gfx.draw_init_text = TRUE;
306 void InitGfxOtherSettings(void)
308 gfx.cursor_mode = CURSOR_DEFAULT;
309 gfx.cursor_mode_override = CURSOR_UNDEFINED;
310 gfx.cursor_mode_final = gfx.cursor_mode;
312 // prevent initially displaying custom mouse cursor in upper left corner
313 gfx.mouse_x = POS_OFFSCREEN;
314 gfx.mouse_y = POS_OFFSCREEN;
317 void InitTileCursorInfo(void)
319 tile_cursor.enabled = FALSE;
320 tile_cursor.active = FALSE;
321 tile_cursor.moving = FALSE;
323 tile_cursor.xpos = 0;
324 tile_cursor.ypos = 0;
327 tile_cursor.target_x = 0;
328 tile_cursor.target_y = 0;
333 tile_cursor.xsn_debug = FALSE;
336 void InitOverlayInfo(void)
338 overlay.enabled = FALSE;
339 overlay.active = FALSE;
341 overlay.show_grid = FALSE;
343 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
344 overlay.grid_button_action = JOY_NO_ACTION;
346 SetOverlayGridSizeAndButtons();
348 #if defined(USE_TOUCH_INPUT_OVERLAY)
349 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
350 overlay.enabled = TRUE;
354 void SetOverlayGridSizeAndButtons(void)
356 int nr = GRID_ACTIVE_NR();
359 overlay.grid_xsize = setup.touch.grid_xsize[nr];
360 overlay.grid_ysize = setup.touch.grid_ysize[nr];
362 for (x = 0; x < MAX_GRID_XSIZE; x++)
363 for (y = 0; y < MAX_GRID_YSIZE; y++)
364 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
367 void SetTileCursorEnabled(boolean enabled)
369 tile_cursor.enabled = enabled;
372 void SetTileCursorActive(boolean active)
374 tile_cursor.active = active;
377 void SetTileCursorTargetXY(int x, int y)
379 // delayed placement of tile selection cursor at target position
380 // (tile cursor will be moved to target position step by step)
382 tile_cursor.xpos = x;
383 tile_cursor.ypos = y;
384 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
385 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
387 tile_cursor.moving = TRUE;
390 void SetTileCursorXY(int x, int y)
392 // immediate placement of tile selection cursor at target position
394 SetTileCursorTargetXY(x, y);
396 tile_cursor.x = tile_cursor.target_x;
397 tile_cursor.y = tile_cursor.target_y;
399 tile_cursor.moving = FALSE;
402 void SetTileCursorSXSY(int sx, int sy)
408 void SetOverlayEnabled(boolean enabled)
410 overlay.enabled = enabled;
413 void SetOverlayActive(boolean active)
415 overlay.active = active;
418 void SetOverlayShowGrid(boolean show_grid)
420 overlay.show_grid = show_grid;
422 SetOverlayActive(show_grid);
425 SetOverlayEnabled(TRUE);
428 boolean GetOverlayEnabled(void)
430 return overlay.enabled;
433 boolean GetOverlayActive(void)
435 return overlay.active;
438 void SetDrawDeactivationMask(int draw_deactivation_mask)
440 gfx.draw_deactivation_mask = draw_deactivation_mask;
443 int GetDrawDeactivationMask(void)
445 return gfx.draw_deactivation_mask;
448 void SetDrawBackgroundMask(int draw_background_mask)
450 gfx.draw_background_mask = draw_background_mask;
453 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask,
454 int x, int y, int width, int height)
456 if (background_bitmap_tile != NULL)
457 gfx.background_bitmap_mask |= mask;
459 gfx.background_bitmap_mask &= ~mask;
461 if (background_bitmap_tile == NULL) // empty background requested
464 if (mask == REDRAW_ALL)
465 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
467 0, 0, video.width, video.height);
468 else if (mask == REDRAW_FIELD)
469 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
471 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
472 else if (mask == REDRAW_DOOR_1)
473 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
475 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
479 // ============================================================================
481 // ============================================================================
483 static int GetRealDepth(int depth)
485 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
488 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
489 int width, int height, Pixel color)
491 SDLFillRectangle(bitmap, x, y, width, height, color);
493 if (bitmap == backbuffer)
494 SetRedrawMaskFromArea(x, y, width, height);
497 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
498 int src_x, int src_y, int width, int height,
499 int dst_x, int dst_y, int mask_mode)
501 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
502 dst_x, dst_y, mask_mode);
504 if (dst_bitmap == backbuffer)
505 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
508 void LimitScreenUpdates(boolean enable)
510 SDLLimitScreenUpdates(enable);
513 void InitVideoDefaults(void)
515 video.default_depth = 32;
518 void InitVideoDisplay(void)
520 if (program.headless)
523 SDLInitVideoDisplay();
527 void CloseVideoDisplay(void)
529 KeyboardAutoRepeatOn();
531 SDL_QuitSubSystem(SDL_INIT_VIDEO);
534 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
537 video.height = height;
538 video.depth = GetRealDepth(depth);
540 video.screen_width = width;
541 video.screen_height = height;
542 video.screen_xoffset = 0;
543 video.screen_yoffset = 0;
545 video.fullscreen_available = FULLSCREEN_STATUS;
546 video.fullscreen_enabled = FALSE;
548 video.window_scaling_available = WINDOW_SCALING_STATUS;
550 video.frame_counter = 0;
551 video.frame_delay.count = 0;
552 video.frame_delay.value = GAME_FRAME_DELAY;
554 video.shifted_up = FALSE;
555 video.shifted_up_pos = 0;
556 video.shifted_up_pos_last = 0;
557 video.shifted_up_delay.count = 0;
558 video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
560 SDLInitVideoBuffer(fullscreen);
562 video.initialized = !program.headless;
567 static void FreeBitmapPointers(Bitmap *bitmap)
572 SDLFreeBitmapPointers(bitmap);
574 checked_free(bitmap->source_filename);
575 bitmap->source_filename = NULL;
578 static void TransferBitmapPointers(Bitmap *src_bitmap,
581 if (src_bitmap == NULL || dst_bitmap == NULL)
584 FreeBitmapPointers(dst_bitmap);
586 *dst_bitmap = *src_bitmap;
589 void FreeBitmap(Bitmap *bitmap)
594 FreeBitmapPointers(bitmap);
599 Bitmap *CreateBitmapStruct(void)
601 return checked_calloc(sizeof(Bitmap));
604 Bitmap *CreateBitmap(int width, int height, int depth)
606 Bitmap *new_bitmap = CreateBitmapStruct();
607 int real_width = MAX(1, width); // prevent zero bitmap width
608 int real_height = MAX(1, height); // prevent zero bitmap height
609 int real_depth = GetRealDepth(depth);
611 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
613 new_bitmap->width = real_width;
614 new_bitmap->height = real_height;
619 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
623 // if new bitmap size fits into old one, no need to re-create it
624 if (width <= (*bitmap)->width &&
625 height <= (*bitmap)->height)
628 // else adjust size so that old and new bitmap size fit into it
629 width = MAX(width, (*bitmap)->width);
630 height = MAX(height, (*bitmap)->height);
633 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
637 *bitmap = new_bitmap;
641 TransferBitmapPointers(new_bitmap, *bitmap);
647 static void CloseWindow(DrawWindow *window)
652 void SetRedrawMaskFromArea(int x, int y, int width, int height)
656 int x2 = x + width - 1;
657 int y2 = y + height - 1;
659 if (width == 0 || height == 0)
662 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
663 redraw_mask |= REDRAW_FIELD;
664 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
665 redraw_mask |= REDRAW_DOOR_1;
666 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
667 redraw_mask |= REDRAW_DOOR_2;
668 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
669 redraw_mask |= REDRAW_DOOR_3;
671 redraw_mask = REDRAW_ALL;
674 static boolean CheckDrawingArea(int x, int y, int draw_mask)
676 if (draw_mask == REDRAW_NONE)
679 if (draw_mask & REDRAW_ALL)
682 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
685 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
688 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
691 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
697 boolean DrawingDeactivatedField(void)
699 if (program.headless)
702 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
708 boolean DrawingDeactivated(int x, int y)
710 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
713 boolean DrawingOnBackground(int x, int y)
715 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
716 CheckDrawingArea(x, y, gfx.draw_background_mask));
719 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
720 int *width, int *height, boolean is_dest)
722 int clip_x, clip_y, clip_width, clip_height;
724 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
726 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
727 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
728 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
729 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
735 clip_width = bitmap->width;
736 clip_height = bitmap->height;
739 // skip if rectangle completely outside bitmap
741 if (*x + *width <= clip_x ||
742 *y + *height <= clip_y ||
743 *x >= clip_x + clip_width ||
744 *y >= clip_y + clip_height)
747 // clip if rectangle overlaps bitmap
751 *width -= clip_x - *x;
754 else if (*x + *width > clip_x + clip_width)
756 *width = clip_x + clip_width - *x;
761 *height -= clip_y - *y;
764 else if (*y + *height > clip_y + clip_height)
766 *height = clip_y + clip_height - *y;
772 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
773 int src_x, int src_y, int width, int height,
774 int dst_x, int dst_y)
776 int dst_x_unclipped = dst_x;
777 int dst_y_unclipped = dst_y;
779 if (program.headless)
782 if (src_bitmap == NULL || dst_bitmap == NULL)
785 if (DrawingDeactivated(dst_x, dst_y))
788 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
789 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
792 // source x/y might need adjustment if destination x/y was clipped top/left
793 src_x += dst_x - dst_x_unclipped;
794 src_y += dst_y - dst_y_unclipped;
796 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
797 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
798 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
799 but is already fixed in SVN and should therefore finally be fixed with
800 the next official SDL release, which is probably version 1.2.14.) */
801 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
803 if (src_bitmap == dst_bitmap)
805 // needed when blitting directly to same bitmap -- should not be needed with
806 // recent SDL libraries, but apparently does not work in 1.2.11 directly
808 static Bitmap *tmp_bitmap = NULL;
809 static int tmp_bitmap_xsize = 0;
810 static int tmp_bitmap_ysize = 0;
812 // start with largest static bitmaps for initial bitmap size ...
813 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
815 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
816 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
819 // ... and allow for later re-adjustments due to custom artwork bitmaps
820 if (src_bitmap->width > tmp_bitmap_xsize ||
821 src_bitmap->height > tmp_bitmap_ysize)
823 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
824 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
826 FreeBitmap(tmp_bitmap);
831 if (tmp_bitmap == NULL)
832 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
835 sysCopyArea(src_bitmap, tmp_bitmap,
836 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
837 sysCopyArea(tmp_bitmap, dst_bitmap,
838 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
843 sysCopyArea(src_bitmap, dst_bitmap,
844 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
847 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
848 int src_x, int src_y, int src_width, int src_height,
849 int dst_x, int dst_y, int dst_width, int dst_height)
851 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
852 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
853 int dst_xsize = dst_width;
854 int dst_ysize = dst_height;
855 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
856 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
859 for (y = 0; y < src_ysteps; y++)
861 for (x = 0; x < src_xsteps; x++)
863 int draw_x = dst_x + x * src_xsize;
864 int draw_y = dst_y + y * src_ysize;
865 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
866 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
868 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
874 void FadeRectangle(int x, int y, int width, int height,
875 int fade_mode, int fade_delay, int post_delay,
876 void (*draw_border_function)(void))
878 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
879 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
882 SDLFadeRectangle(x, y, width, height,
883 fade_mode, fade_delay, post_delay, draw_border_function);
886 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
889 if (program.headless)
892 if (DrawingDeactivated(x, y))
895 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
898 sysFillRectangle(bitmap, x, y, width, height, color);
901 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
903 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
906 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
907 int width, int height)
909 if (DrawingOnBackground(x, y))
910 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
912 ClearRectangle(bitmap, x, y, width, height);
915 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
916 int src_x, int src_y, int width, int height,
917 int dst_x, int dst_y)
919 if (DrawingDeactivated(dst_x, dst_y))
922 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
923 dst_x, dst_y, BLIT_MASKED);
926 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
927 int src_x, int src_y, int width, int height,
928 int dst_x, int dst_y)
930 if (DrawingOnBackground(dst_x, dst_y))
933 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
937 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
941 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
945 void BlitTexture(Bitmap *bitmap,
946 int src_x, int src_y, int width, int height,
947 int dst_x, int dst_y)
952 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
956 void BlitTextureMasked(Bitmap *bitmap,
957 int src_x, int src_y, int width, int height,
958 int dst_x, int dst_y)
963 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
967 void BlitToScreen(Bitmap *bitmap,
968 int src_x, int src_y, int width, int height,
969 int dst_x, int dst_y)
974 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
975 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
976 width, height, dst_x, dst_y);
978 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
981 void BlitToScreenMasked(Bitmap *bitmap,
982 int src_x, int src_y, int width, int height,
983 int dst_x, int dst_y)
988 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
989 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
990 width, height, dst_x, dst_y);
992 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
995 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
998 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1001 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1002 int to_x, int to_y, Pixel pixel, int line_width)
1006 if (program.headless)
1009 for (x = 0; x < line_width; x++)
1011 for (y = 0; y < line_width; y++)
1013 int dx = x - line_width / 2;
1014 int dy = y - line_width / 2;
1016 if ((x == 0 && y == 0) ||
1017 (x == 0 && y == line_width - 1) ||
1018 (x == line_width - 1 && y == 0) ||
1019 (x == line_width - 1 && y == line_width - 1))
1023 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1028 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1033 for (i = 0; i < num_points - 1; i++)
1034 DrawLine(bitmap, points[i].x, points[i].y,
1035 points[i + 1].x, points[i + 1].y, pixel, line_width);
1038 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1042 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1044 if (program.headless)
1047 if (x < 0 || x >= bitmap->width ||
1048 y < 0 || y >= bitmap->height)
1051 return SDLGetPixel(bitmap, x, y);
1054 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1055 unsigned int color_g, unsigned int color_b)
1057 if (program.headless)
1060 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1063 void KeyboardAutoRepeatOn(void)
1065 keyrepeat_status = TRUE;
1068 void KeyboardAutoRepeatOff(void)
1070 keyrepeat_status = FALSE;
1073 boolean SetVideoMode(boolean fullscreen)
1075 return SDLSetVideoMode(fullscreen);
1078 void SetVideoFrameDelay(unsigned int frame_delay_value)
1080 video.frame_delay.value = frame_delay_value;
1083 unsigned int GetVideoFrameDelay(void)
1085 return video.frame_delay.value;
1088 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1090 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1091 (!fullscreen && video.fullscreen_enabled))
1092 fullscreen = SetVideoMode(fullscreen);
1097 Bitmap *LoadImage(char *filename)
1101 new_bitmap = SDLLoadImage(filename);
1104 new_bitmap->source_filename = getStringCopy(filename);
1109 Bitmap *LoadCustomImage(char *basename)
1111 char *filename = getCustomImageFilename(basename);
1114 if (filename == NULL)
1115 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1117 if ((new_bitmap = LoadImage(filename)) == NULL)
1118 Fail("LoadImage('%s') failed", basename);
1123 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1125 char *filename = getCustomImageFilename(basename);
1128 if (filename == NULL) // (should never happen)
1130 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1135 if (strEqual(filename, bitmap->source_filename))
1137 // The old and new image are the same (have the same filename and path).
1138 // This usually means that this image does not exist in this graphic set
1139 // and a fallback to the existing image is done.
1144 if ((new_bitmap = LoadImage(filename)) == NULL)
1146 Warn("LoadImage('%s') failed", basename);
1151 if (bitmap->width != new_bitmap->width ||
1152 bitmap->height != new_bitmap->height)
1154 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1157 FreeBitmap(new_bitmap);
1162 TransferBitmapPointers(new_bitmap, bitmap);
1166 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1168 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1171 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1173 if (bitmaps[IMG_BITMAP_CUSTOM])
1175 // check if original sized bitmap points to custom sized bitmap
1176 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1178 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1180 // keep pointer of previous custom size bitmap
1181 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1183 // set original bitmap pointer to scaled original bitmap of other size
1184 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1186 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1190 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1193 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1196 if (gfx.game_tile_size == gfx.standard_tile_size)
1198 // set game bitmap pointer to standard sized bitmap (already existing)
1199 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1204 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1205 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1206 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1208 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1210 // set game bitmap pointer to custom sized bitmap (newly created)
1211 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1214 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1215 int tile_size, boolean create_small_bitmaps)
1217 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1218 Bitmap *tmp_bitmap_final = NULL;
1219 Bitmap *tmp_bitmap_0 = NULL;
1220 Bitmap *tmp_bitmap_1 = NULL;
1221 Bitmap *tmp_bitmap_2 = NULL;
1222 Bitmap *tmp_bitmap_4 = NULL;
1223 Bitmap *tmp_bitmap_8 = NULL;
1224 Bitmap *tmp_bitmap_16 = NULL;
1225 Bitmap *tmp_bitmap_32 = NULL;
1226 int width_final, height_final;
1227 int width_0, height_0;
1228 int width_1, height_1;
1229 int width_2, height_2;
1230 int width_4, height_4;
1231 int width_8, height_8;
1232 int width_16, height_16;
1233 int width_32, height_32;
1234 int old_width, old_height;
1237 print_timestamp_init("CreateScaledBitmaps");
1239 old_width = old_bitmap->width;
1240 old_height = old_bitmap->height;
1242 // calculate new image dimensions for final image size
1243 width_final = old_width * zoom_factor;
1244 height_final = old_height * zoom_factor;
1246 // get image with final size (this might require scaling up)
1247 // ("final" size may result in non-standard tile size image)
1248 if (zoom_factor != 1)
1249 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1251 tmp_bitmap_final = old_bitmap;
1253 UPDATE_BUSY_STATE();
1255 width_0 = width_1 = width_final;
1256 height_0 = height_1 = height_final;
1258 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1260 if (create_small_bitmaps)
1262 // check if we have a non-gameplay tile size image
1263 if (tile_size != gfx.game_tile_size)
1265 // get image with gameplay tile size
1266 width_0 = width_final * gfx.game_tile_size / tile_size;
1267 height_0 = height_final * gfx.game_tile_size / tile_size;
1269 if (width_0 == old_width)
1270 tmp_bitmap_0 = old_bitmap;
1271 else if (width_0 == width_final)
1272 tmp_bitmap_0 = tmp_bitmap_final;
1274 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1276 UPDATE_BUSY_STATE();
1279 // check if we have a non-standard tile size image
1280 if (tile_size != gfx.standard_tile_size)
1282 // get image with standard tile size
1283 width_1 = width_final * gfx.standard_tile_size / tile_size;
1284 height_1 = height_final * gfx.standard_tile_size / tile_size;
1286 if (width_1 == old_width)
1287 tmp_bitmap_1 = old_bitmap;
1288 else if (width_1 == width_final)
1289 tmp_bitmap_1 = tmp_bitmap_final;
1290 else if (width_1 == width_0)
1291 tmp_bitmap_1 = tmp_bitmap_0;
1293 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1295 UPDATE_BUSY_STATE();
1298 // calculate new image dimensions for small images
1299 width_2 = width_1 / 2;
1300 height_2 = height_1 / 2;
1301 width_4 = width_1 / 4;
1302 height_4 = height_1 / 4;
1303 width_8 = width_1 / 8;
1304 height_8 = height_1 / 8;
1305 width_16 = width_1 / 16;
1306 height_16 = height_1 / 16;
1307 width_32 = width_1 / 32;
1308 height_32 = height_1 / 32;
1310 // get image with 1/2 of normal size (for use in the level editor)
1311 if (width_2 == old_width)
1312 tmp_bitmap_2 = old_bitmap;
1314 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1316 UPDATE_BUSY_STATE();
1318 // get image with 1/4 of normal size (for use in the level editor)
1319 if (width_4 == old_width)
1320 tmp_bitmap_4 = old_bitmap;
1322 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1324 UPDATE_BUSY_STATE();
1326 // get image with 1/8 of normal size (for use on the preview screen)
1327 if (width_8 == old_width)
1328 tmp_bitmap_8 = old_bitmap;
1330 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1332 UPDATE_BUSY_STATE();
1334 // get image with 1/16 of normal size (for use on the preview screen)
1335 if (width_16 == old_width)
1336 tmp_bitmap_16 = old_bitmap;
1338 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1340 UPDATE_BUSY_STATE();
1342 // get image with 1/32 of normal size (for use on the preview screen)
1343 if (width_32 == old_width)
1344 tmp_bitmap_32 = old_bitmap;
1346 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1348 UPDATE_BUSY_STATE();
1350 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1351 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1352 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1353 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1354 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1355 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1357 if (width_0 != width_1)
1358 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1360 if (bitmaps[IMG_BITMAP_CUSTOM])
1361 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1363 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1365 // store the "final" (up-scaled) original bitmap, if not already stored
1367 int tmp_bitmap_final_nr = -1;
1369 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1370 if (bitmaps[i] == tmp_bitmap_final)
1371 tmp_bitmap_final_nr = i;
1373 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1375 // store pointer of scaled original bitmap (not used for any other size)
1376 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1378 // set original bitmap pointer to scaled original bitmap of other size
1379 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1383 // set original bitmap pointer to corresponding sized bitmap
1384 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1387 // free the "old" (unscaled) original bitmap, if not already stored
1389 boolean free_old_bitmap = TRUE;
1391 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1392 if (bitmaps[i] == old_bitmap)
1393 free_old_bitmap = FALSE;
1395 if (free_old_bitmap)
1397 // copy image filename from old to new standard sized bitmap
1398 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1399 getStringCopy(old_bitmap->source_filename);
1401 FreeBitmap(old_bitmap);
1406 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1408 // set original bitmap pointer to corresponding sized bitmap
1409 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1411 if (old_bitmap != tmp_bitmap_1)
1412 FreeBitmap(old_bitmap);
1415 UPDATE_BUSY_STATE();
1417 print_timestamp_done("CreateScaledBitmaps");
1420 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1423 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1426 void CreateBitmapTextures(Bitmap **bitmaps)
1428 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1429 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1431 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1434 void FreeBitmapTextures(Bitmap **bitmaps)
1436 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1437 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1439 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1442 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1444 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1448 // ----------------------------------------------------------------------------
1449 // mouse pointer functions
1450 // ----------------------------------------------------------------------------
1452 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1454 // XPM image definitions
1455 static const char *cursor_image_none[] =
1457 // width height num_colors chars_per_pixel
1487 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1488 static const char *cursor_image_dot[] =
1490 // width height num_colors chars_per_pixel
1519 static const char **cursor_image_playfield = cursor_image_dot;
1521 // some people complained about a "white dot" on the screen and thought it
1522 // was a graphical error... OK, let's just remove the whole pointer :-)
1523 static const char **cursor_image_playfield = cursor_image_none;
1526 static const int cursor_bit_order = BIT_ORDER_MSB;
1528 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1530 struct MouseCursorInfo *cursor;
1531 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1532 int header_lines = 4;
1535 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1537 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1540 for (y = 0; y < cursor->width; y++)
1542 for (x = 0; x < cursor->height; x++)
1545 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1550 cursor->data[i] = cursor->mask[i] = 0;
1553 switch (image[header_lines + y][x])
1556 cursor->data[i] |= bit_mask;
1557 cursor->mask[i] |= bit_mask;
1561 cursor->mask[i] |= bit_mask;
1570 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1575 void SetMouseCursor(int mode)
1577 static struct MouseCursorInfo *cursor_none = NULL;
1578 static struct MouseCursorInfo *cursor_playfield = NULL;
1579 struct MouseCursorInfo *cursor_new;
1580 int mode_final = mode;
1582 if (cursor_none == NULL)
1583 cursor_none = get_cursor_from_image(cursor_image_none);
1585 if (cursor_playfield == NULL)
1586 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1588 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1589 mode_final = gfx.cursor_mode_override;
1591 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1592 mode_final == CURSOR_NONE ? cursor_none :
1593 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1595 SDLSetMouseCursor(cursor_new);
1597 gfx.cursor_mode = mode;
1598 gfx.cursor_mode_final = mode_final;
1601 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1603 // mouse events do not contain logical screen size corrections yet
1604 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1606 mouse_x -= video.screen_xoffset;
1607 mouse_y -= video.screen_yoffset;
1609 gfx.mouse_x = mouse_x;
1610 gfx.mouse_y = mouse_y;
1613 void UpdateMousePosition(void)
1615 int mouse_x, mouse_y;
1618 SDL_GetMouseState(&mouse_x, &mouse_y);
1620 UpdateRawMousePosition(mouse_x, mouse_y);
1624 // ============================================================================
1626 // ============================================================================
1628 void OpenAudio(void)
1630 // always start with reliable default values
1631 audio.sound_available = FALSE;
1632 audio.music_available = FALSE;
1633 audio.loops_available = FALSE;
1635 audio.sound_enabled = FALSE;
1636 audio.sound_deactivated = FALSE;
1638 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1639 audio.mixer_pid = 0;
1640 audio.device_name = NULL;
1641 audio.device_fd = -1;
1643 audio.num_channels = 0;
1644 audio.music_channel = 0;
1645 audio.first_sound_channel = 0;
1650 void CloseAudio(void)
1654 audio.sound_enabled = FALSE;
1657 void SetAudioMode(boolean enabled)
1659 if (!audio.sound_available)
1662 audio.sound_enabled = enabled;
1666 // ============================================================================
1668 // ============================================================================
1670 void InitEventFilter(EventFilter filter_function)
1672 SDL_SetEventFilter(filter_function, NULL);
1675 boolean PendingEvent(void)
1677 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1680 void WaitEvent(Event *event)
1682 SDLWaitEvent(event);
1685 void PeekEvent(Event *event)
1687 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1690 void PumpEvents(void)
1695 void CheckQuitEvent(void)
1697 if (SDL_QuitRequested())
1698 program.exit_function(0);
1701 Key GetEventKey(KeyEvent *event)
1703 // key up/down events in SDL2 do not return text characters anymore
1704 return event->keysym.sym;
1707 KeyMod HandleKeyModState(Key key, int key_status)
1709 static KeyMod current_modifiers = KMOD_None;
1711 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1713 KeyMod new_modifier = KMOD_None;
1718 new_modifier = KMOD_Shift_L;
1721 new_modifier = KMOD_Shift_R;
1723 case KSYM_Control_L:
1724 new_modifier = KMOD_Control_L;
1726 case KSYM_Control_R:
1727 new_modifier = KMOD_Control_R;
1730 new_modifier = KMOD_Meta_L;
1733 new_modifier = KMOD_Meta_R;
1736 new_modifier = KMOD_Alt_L;
1739 new_modifier = KMOD_Alt_R;
1745 if (key_status == KEY_PRESSED)
1746 current_modifiers |= new_modifier;
1748 current_modifiers &= ~new_modifier;
1751 return current_modifiers;
1754 KeyMod GetKeyModState(void)
1756 return (KeyMod)SDL_GetModState();
1759 KeyMod GetKeyModStateFromEvents(void)
1761 /* always use key modifier state as tracked from key events (this is needed
1762 if the modifier key event was injected into the event queue, but the key
1763 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1764 query the keys as held pressed on the keyboard) -- this case is currently
1765 only used to filter out clipboard insert events from "True X-Mouse" tool */
1767 return HandleKeyModState(KSYM_UNDEFINED, 0);
1770 void StartTextInput(int x, int y, int width, int height)
1772 textinput_status = TRUE;
1774 #if defined(HAS_SCREEN_KEYBOARD)
1775 SDL_StartTextInput();
1777 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1779 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1780 video.shifted_up_delay.count = SDL_GetTicks();
1781 video.shifted_up = TRUE;
1786 void StopTextInput(void)
1788 textinput_status = FALSE;
1790 #if defined(HAS_SCREEN_KEYBOARD)
1791 SDL_StopTextInput();
1793 if (video.shifted_up)
1795 video.shifted_up_pos = 0;
1796 video.shifted_up_delay.count = SDL_GetTicks();
1797 video.shifted_up = FALSE;
1802 void PushUserEvent(int code, int value1, int value2)
1806 SDL_memset(&event, 0, sizeof(event));
1808 event.type = EVENT_USER;
1810 event.value1 = value1;
1811 event.value2 = value2;
1813 SDL_PushEvent((SDL_Event *)&event);
1816 boolean PendingEscapeKeyEvent(void)
1822 // check if any key press event is pending
1823 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1826 // check if pressed key is "Escape" key
1827 if (event.key.keysym.sym == KSYM_Escape)
1835 // ============================================================================
1836 // joystick functions
1837 // ============================================================================
1839 void InitJoysticks(void)
1843 #if defined(NO_JOYSTICK)
1844 return; // joysticks generally deactivated by compile-time directive
1847 // always start with reliable default values
1848 joystick.status = JOYSTICK_NOT_AVAILABLE;
1849 for (i = 0; i < MAX_PLAYERS; i++)
1850 joystick.nr[i] = -1; // no joystick configured
1855 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1857 return SDLReadJoystick(nr, x, y, b1, b2);
1860 boolean CheckJoystickOpened(int nr)
1862 return SDLCheckJoystickOpened(nr);
1865 void ClearJoystickState(void)
1867 SDLClearJoystickState();
1871 // ============================================================================
1872 // Emscripten functions
1873 // ============================================================================
1875 void InitEmscriptenFilesystem(void)
1877 #if defined(PLATFORM_EMSCRIPTEN)
1880 dir = UTF8ToString($0);
1882 Module.sync_done = 0;
1884 FS.mkdir(dir); // create persistent data directory
1885 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1886 FS.syncfs(true, function(err) // sync persistent data into memory
1889 Module.sync_done = 1;
1891 }, PERSISTENT_DIRECTORY);
1893 // wait for persistent data to be synchronized to memory
1894 while (emscripten_run_script_int("Module.sync_done") == 0)
1899 void SyncEmscriptenFilesystem(void)
1901 #if defined(PLATFORM_EMSCRIPTEN)
1904 FS.syncfs(function(err)