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 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask,
453 int x, int y, int width, int height)
455 if (background_bitmap_tile != NULL)
456 gfx.background_bitmap_mask |= mask;
458 gfx.background_bitmap_mask &= ~mask;
460 if (background_bitmap_tile == NULL) // empty background requested
463 if (mask == REDRAW_ALL)
464 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
466 0, 0, video.width, video.height);
467 else if (mask == REDRAW_FIELD)
468 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
470 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
471 else if (mask == REDRAW_DOOR_1)
472 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
474 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
478 // ============================================================================
480 // ============================================================================
482 static int GetRealDepth(int depth)
484 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
487 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
488 int width, int height, Pixel color)
490 SDLFillRectangle(bitmap, x, y, width, height, color);
492 if (bitmap == backbuffer)
493 SetRedrawMaskFromArea(x, y, width, height);
496 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
497 int src_x, int src_y, int width, int height,
498 int dst_x, int dst_y, int mask_mode)
500 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
501 dst_x, dst_y, mask_mode);
503 if (dst_bitmap == backbuffer)
504 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
507 void LimitScreenUpdates(boolean enable)
509 SDLLimitScreenUpdates(enable);
512 void InitVideoDefaults(void)
514 video.default_depth = 32;
517 void InitVideoDisplay(void)
519 if (program.headless)
522 SDLInitVideoDisplay();
526 void CloseVideoDisplay(void)
528 KeyboardAutoRepeatOn();
530 SDL_QuitSubSystem(SDL_INIT_VIDEO);
533 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
536 video.height = height;
537 video.depth = GetRealDepth(depth);
539 video.screen_width = width;
540 video.screen_height = height;
541 video.screen_xoffset = 0;
542 video.screen_yoffset = 0;
544 video.fullscreen_available = FULLSCREEN_STATUS;
545 video.fullscreen_enabled = FALSE;
547 video.window_scaling_available = WINDOW_SCALING_STATUS;
549 video.frame_counter = 0;
550 video.frame_delay.count = 0;
551 video.frame_delay.value = GAME_FRAME_DELAY;
553 video.shifted_up = FALSE;
554 video.shifted_up_pos = 0;
555 video.shifted_up_pos_last = 0;
556 video.shifted_up_delay.count = 0;
557 video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
559 SDLInitVideoBuffer(fullscreen);
561 video.initialized = !program.headless;
566 static void FreeBitmapPointers(Bitmap *bitmap)
571 SDLFreeBitmapPointers(bitmap);
573 checked_free(bitmap->source_filename);
574 bitmap->source_filename = NULL;
577 static void TransferBitmapPointers(Bitmap *src_bitmap,
580 if (src_bitmap == NULL || dst_bitmap == NULL)
583 FreeBitmapPointers(dst_bitmap);
585 *dst_bitmap = *src_bitmap;
588 void FreeBitmap(Bitmap *bitmap)
593 FreeBitmapPointers(bitmap);
598 Bitmap *CreateBitmapStruct(void)
600 return checked_calloc(sizeof(Bitmap));
603 Bitmap *CreateBitmap(int width, int height, int depth)
605 Bitmap *new_bitmap = CreateBitmapStruct();
606 int real_width = MAX(1, width); // prevent zero bitmap width
607 int real_height = MAX(1, height); // prevent zero bitmap height
608 int real_depth = GetRealDepth(depth);
610 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
612 new_bitmap->width = real_width;
613 new_bitmap->height = real_height;
618 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
622 // if new bitmap size fits into old one, no need to re-create it
623 if (width <= (*bitmap)->width &&
624 height <= (*bitmap)->height)
627 // else adjust size so that old and new bitmap size fit into it
628 width = MAX(width, (*bitmap)->width);
629 height = MAX(height, (*bitmap)->height);
632 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
636 *bitmap = new_bitmap;
640 TransferBitmapPointers(new_bitmap, *bitmap);
646 static void CloseWindow(DrawWindow *window)
651 void SetRedrawMaskFromArea(int x, int y, int width, int height)
655 int x2 = x + width - 1;
656 int y2 = y + height - 1;
658 if (width == 0 || height == 0)
661 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
662 redraw_mask |= REDRAW_FIELD;
663 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
664 redraw_mask |= REDRAW_DOOR_1;
665 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
666 redraw_mask |= REDRAW_DOOR_2;
667 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
668 redraw_mask |= REDRAW_DOOR_3;
670 redraw_mask = REDRAW_ALL;
673 static boolean CheckDrawingArea(int x, int y, int draw_mask)
675 if (draw_mask == REDRAW_NONE)
678 if (draw_mask & REDRAW_ALL)
681 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
684 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
687 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
690 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
696 boolean DrawingDeactivatedField(void)
698 if (program.headless)
701 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
707 boolean DrawingDeactivated(int x, int y)
709 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
712 boolean DrawingOnBackground(int x, int y)
714 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
715 CheckDrawingArea(x, y, gfx.draw_background_mask));
718 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
719 int *width, int *height, boolean is_dest)
721 int clip_x, clip_y, clip_width, clip_height;
723 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
725 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
726 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
727 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
728 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
734 clip_width = bitmap->width;
735 clip_height = bitmap->height;
738 // skip if rectangle completely outside bitmap
740 if (*x + *width <= clip_x ||
741 *y + *height <= clip_y ||
742 *x >= clip_x + clip_width ||
743 *y >= clip_y + clip_height)
746 // clip if rectangle overlaps bitmap
750 *width -= clip_x - *x;
753 else if (*x + *width > clip_x + clip_width)
755 *width = clip_x + clip_width - *x;
760 *height -= clip_y - *y;
763 else if (*y + *height > clip_y + clip_height)
765 *height = clip_y + clip_height - *y;
771 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
772 int src_x, int src_y, int width, int height,
773 int dst_x, int dst_y)
775 int dst_x_unclipped = dst_x;
776 int dst_y_unclipped = dst_y;
778 if (program.headless)
781 if (src_bitmap == NULL || dst_bitmap == NULL)
784 if (DrawingDeactivated(dst_x, dst_y))
787 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
788 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
791 // source x/y might need adjustment if destination x/y was clipped top/left
792 src_x += dst_x - dst_x_unclipped;
793 src_y += dst_y - dst_y_unclipped;
795 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
796 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
797 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
798 but is already fixed in SVN and should therefore finally be fixed with
799 the next official SDL release, which is probably version 1.2.14.) */
800 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
802 if (src_bitmap == dst_bitmap)
804 // needed when blitting directly to same bitmap -- should not be needed with
805 // recent SDL libraries, but apparently does not work in 1.2.11 directly
807 static Bitmap *tmp_bitmap = NULL;
808 static int tmp_bitmap_xsize = 0;
809 static int tmp_bitmap_ysize = 0;
811 // start with largest static bitmaps for initial bitmap size ...
812 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
814 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
815 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
818 // ... and allow for later re-adjustments due to custom artwork bitmaps
819 if (src_bitmap->width > tmp_bitmap_xsize ||
820 src_bitmap->height > tmp_bitmap_ysize)
822 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
823 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
825 FreeBitmap(tmp_bitmap);
830 if (tmp_bitmap == NULL)
831 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
834 sysCopyArea(src_bitmap, tmp_bitmap,
835 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
836 sysCopyArea(tmp_bitmap, dst_bitmap,
837 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
842 sysCopyArea(src_bitmap, dst_bitmap,
843 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
846 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
847 int src_x, int src_y, int src_width, int src_height,
848 int dst_x, int dst_y, int dst_width, int dst_height)
850 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
851 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
852 int dst_xsize = dst_width;
853 int dst_ysize = dst_height;
854 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
855 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
858 for (y = 0; y < src_ysteps; y++)
860 for (x = 0; x < src_xsteps; x++)
862 int draw_x = dst_x + x * src_xsize;
863 int draw_y = dst_y + y * src_ysize;
864 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
865 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
867 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
873 void FadeRectangle(int x, int y, int width, int height,
874 int fade_mode, int fade_delay, int post_delay,
875 void (*draw_border_function)(void))
877 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
878 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
881 SDLFadeRectangle(x, y, width, height,
882 fade_mode, fade_delay, post_delay, draw_border_function);
885 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
888 if (program.headless)
891 if (DrawingDeactivated(x, y))
894 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
897 sysFillRectangle(bitmap, x, y, width, height, color);
900 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
902 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
905 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
906 int width, int height)
908 if (DrawingOnBackground(x, y))
909 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
911 ClearRectangle(bitmap, x, y, width, height);
914 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
915 int src_x, int src_y, int width, int height,
916 int dst_x, int dst_y)
918 if (DrawingDeactivated(dst_x, dst_y))
921 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
922 dst_x, dst_y, BLIT_MASKED);
925 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
926 int src_x, int src_y, int width, int height,
927 int dst_x, int dst_y)
929 if (DrawingOnBackground(dst_x, dst_y))
932 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
936 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
940 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
944 void BlitTexture(Bitmap *bitmap,
945 int src_x, int src_y, int width, int height,
946 int dst_x, int dst_y)
951 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
955 void BlitTextureMasked(Bitmap *bitmap,
956 int src_x, int src_y, int width, int height,
957 int dst_x, int dst_y)
962 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
966 void BlitToScreen(Bitmap *bitmap,
967 int src_x, int src_y, int width, int height,
968 int dst_x, int dst_y)
973 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
974 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
975 width, height, dst_x, dst_y);
977 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
980 void BlitToScreenMasked(Bitmap *bitmap,
981 int src_x, int src_y, int width, int height,
982 int dst_x, int dst_y)
987 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
988 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
989 width, height, dst_x, dst_y);
991 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
994 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
997 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1000 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1001 int to_x, int to_y, Pixel pixel, int line_width)
1005 if (program.headless)
1008 for (x = 0; x < line_width; x++)
1010 for (y = 0; y < line_width; y++)
1012 int dx = x - line_width / 2;
1013 int dy = y - line_width / 2;
1015 if ((x == 0 && y == 0) ||
1016 (x == 0 && y == line_width - 1) ||
1017 (x == line_width - 1 && y == 0) ||
1018 (x == line_width - 1 && y == line_width - 1))
1022 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1027 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1032 for (i = 0; i < num_points - 1; i++)
1033 DrawLine(bitmap, points[i].x, points[i].y,
1034 points[i + 1].x, points[i + 1].y, pixel, line_width);
1037 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1041 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1043 if (program.headless)
1046 if (x < 0 || x >= bitmap->width ||
1047 y < 0 || y >= bitmap->height)
1050 return SDLGetPixel(bitmap, x, y);
1053 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1054 unsigned int color_g, unsigned int color_b)
1056 if (program.headless)
1059 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1062 void KeyboardAutoRepeatOn(void)
1064 keyrepeat_status = TRUE;
1067 void KeyboardAutoRepeatOff(void)
1069 keyrepeat_status = FALSE;
1072 boolean SetVideoMode(boolean fullscreen)
1074 return SDLSetVideoMode(fullscreen);
1077 void SetVideoFrameDelay(unsigned int frame_delay_value)
1079 video.frame_delay.value = frame_delay_value;
1082 unsigned int GetVideoFrameDelay(void)
1084 return video.frame_delay.value;
1087 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1089 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1090 (!fullscreen && video.fullscreen_enabled))
1091 fullscreen = SetVideoMode(fullscreen);
1096 Bitmap *LoadImage(char *filename)
1100 new_bitmap = SDLLoadImage(filename);
1103 new_bitmap->source_filename = getStringCopy(filename);
1108 Bitmap *LoadCustomImage(char *basename)
1110 char *filename = getCustomImageFilename(basename);
1113 if (filename == NULL)
1114 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1116 if ((new_bitmap = LoadImage(filename)) == NULL)
1117 Fail("LoadImage('%s') failed", basename);
1122 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1124 char *filename = getCustomImageFilename(basename);
1127 if (filename == NULL) // (should never happen)
1129 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1134 if (strEqual(filename, bitmap->source_filename))
1136 // The old and new image are the same (have the same filename and path).
1137 // This usually means that this image does not exist in this graphic set
1138 // and a fallback to the existing image is done.
1143 if ((new_bitmap = LoadImage(filename)) == NULL)
1145 Warn("LoadImage('%s') failed", basename);
1150 if (bitmap->width != new_bitmap->width ||
1151 bitmap->height != new_bitmap->height)
1153 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1156 FreeBitmap(new_bitmap);
1161 TransferBitmapPointers(new_bitmap, bitmap);
1165 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1167 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1170 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1172 if (bitmaps[IMG_BITMAP_CUSTOM])
1174 // check if original sized bitmap points to custom sized bitmap
1175 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1177 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1179 // keep pointer of previous custom size bitmap
1180 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1182 // set original bitmap pointer to scaled original bitmap of other size
1183 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1185 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1189 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1192 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1195 if (gfx.game_tile_size == gfx.standard_tile_size)
1197 // set game bitmap pointer to standard sized bitmap (already existing)
1198 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1203 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1204 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1205 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1207 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1209 // set game bitmap pointer to custom sized bitmap (newly created)
1210 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1213 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1214 int tile_size, boolean create_small_bitmaps)
1216 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1217 Bitmap *tmp_bitmap_final = NULL;
1218 Bitmap *tmp_bitmap_0 = NULL;
1219 Bitmap *tmp_bitmap_1 = NULL;
1220 Bitmap *tmp_bitmap_2 = NULL;
1221 Bitmap *tmp_bitmap_4 = NULL;
1222 Bitmap *tmp_bitmap_8 = NULL;
1223 Bitmap *tmp_bitmap_16 = NULL;
1224 Bitmap *tmp_bitmap_32 = NULL;
1225 int width_final, height_final;
1226 int width_0, height_0;
1227 int width_1, height_1;
1228 int width_2, height_2;
1229 int width_4, height_4;
1230 int width_8, height_8;
1231 int width_16, height_16;
1232 int width_32, height_32;
1233 int old_width, old_height;
1236 print_timestamp_init("CreateScaledBitmaps");
1238 old_width = old_bitmap->width;
1239 old_height = old_bitmap->height;
1241 // calculate new image dimensions for final image size
1242 width_final = old_width * zoom_factor;
1243 height_final = old_height * zoom_factor;
1245 // get image with final size (this might require scaling up)
1246 // ("final" size may result in non-standard tile size image)
1247 if (zoom_factor != 1)
1248 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1250 tmp_bitmap_final = old_bitmap;
1252 UPDATE_BUSY_STATE();
1254 width_0 = width_1 = width_final;
1255 height_0 = height_1 = height_final;
1257 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1259 if (create_small_bitmaps)
1261 // check if we have a non-gameplay tile size image
1262 if (tile_size != gfx.game_tile_size)
1264 // get image with gameplay tile size
1265 width_0 = width_final * gfx.game_tile_size / tile_size;
1266 height_0 = height_final * gfx.game_tile_size / tile_size;
1268 if (width_0 == old_width)
1269 tmp_bitmap_0 = old_bitmap;
1270 else if (width_0 == width_final)
1271 tmp_bitmap_0 = tmp_bitmap_final;
1273 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1275 UPDATE_BUSY_STATE();
1278 // check if we have a non-standard tile size image
1279 if (tile_size != gfx.standard_tile_size)
1281 // get image with standard tile size
1282 width_1 = width_final * gfx.standard_tile_size / tile_size;
1283 height_1 = height_final * gfx.standard_tile_size / tile_size;
1285 if (width_1 == old_width)
1286 tmp_bitmap_1 = old_bitmap;
1287 else if (width_1 == width_final)
1288 tmp_bitmap_1 = tmp_bitmap_final;
1289 else if (width_1 == width_0)
1290 tmp_bitmap_1 = tmp_bitmap_0;
1292 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1294 UPDATE_BUSY_STATE();
1297 // calculate new image dimensions for small images
1298 width_2 = width_1 / 2;
1299 height_2 = height_1 / 2;
1300 width_4 = width_1 / 4;
1301 height_4 = height_1 / 4;
1302 width_8 = width_1 / 8;
1303 height_8 = height_1 / 8;
1304 width_16 = width_1 / 16;
1305 height_16 = height_1 / 16;
1306 width_32 = width_1 / 32;
1307 height_32 = height_1 / 32;
1309 // get image with 1/2 of normal size (for use in the level editor)
1310 if (width_2 == old_width)
1311 tmp_bitmap_2 = old_bitmap;
1313 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1315 UPDATE_BUSY_STATE();
1317 // get image with 1/4 of normal size (for use in the level editor)
1318 if (width_4 == old_width)
1319 tmp_bitmap_4 = old_bitmap;
1321 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1323 UPDATE_BUSY_STATE();
1325 // get image with 1/8 of normal size (for use on the preview screen)
1326 if (width_8 == old_width)
1327 tmp_bitmap_8 = old_bitmap;
1329 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1331 UPDATE_BUSY_STATE();
1333 // get image with 1/16 of normal size (for use on the preview screen)
1334 if (width_16 == old_width)
1335 tmp_bitmap_16 = old_bitmap;
1337 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1339 UPDATE_BUSY_STATE();
1341 // get image with 1/32 of normal size (for use on the preview screen)
1342 if (width_32 == old_width)
1343 tmp_bitmap_32 = old_bitmap;
1345 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1347 UPDATE_BUSY_STATE();
1349 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1350 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1351 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1352 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1353 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1354 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1356 if (width_0 != width_1)
1357 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1359 if (bitmaps[IMG_BITMAP_CUSTOM])
1360 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1362 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1364 // store the "final" (up-scaled) original bitmap, if not already stored
1366 int tmp_bitmap_final_nr = -1;
1368 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1369 if (bitmaps[i] == tmp_bitmap_final)
1370 tmp_bitmap_final_nr = i;
1372 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1374 // store pointer of scaled original bitmap (not used for any other size)
1375 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1377 // set original bitmap pointer to scaled original bitmap of other size
1378 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1382 // set original bitmap pointer to corresponding sized bitmap
1383 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1386 // free the "old" (unscaled) original bitmap, if not already stored
1388 boolean free_old_bitmap = TRUE;
1390 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1391 if (bitmaps[i] == old_bitmap)
1392 free_old_bitmap = FALSE;
1394 if (free_old_bitmap)
1396 // copy image filename from old to new standard sized bitmap
1397 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1398 getStringCopy(old_bitmap->source_filename);
1400 FreeBitmap(old_bitmap);
1405 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1407 // set original bitmap pointer to corresponding sized bitmap
1408 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1410 if (old_bitmap != tmp_bitmap_1)
1411 FreeBitmap(old_bitmap);
1414 UPDATE_BUSY_STATE();
1416 print_timestamp_done("CreateScaledBitmaps");
1419 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1422 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1425 void CreateBitmapTextures(Bitmap **bitmaps)
1427 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1428 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1430 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1433 void FreeBitmapTextures(Bitmap **bitmaps)
1435 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1436 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1438 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1441 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1443 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1447 // ----------------------------------------------------------------------------
1448 // mouse pointer functions
1449 // ----------------------------------------------------------------------------
1451 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1453 // XPM image definitions
1454 static const char *cursor_image_none[] =
1456 // width height num_colors chars_per_pixel
1486 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1487 static const char *cursor_image_dot[] =
1489 // width height num_colors chars_per_pixel
1518 static const char **cursor_image_playfield = cursor_image_dot;
1520 // some people complained about a "white dot" on the screen and thought it
1521 // was a graphical error... OK, let's just remove the whole pointer :-)
1522 static const char **cursor_image_playfield = cursor_image_none;
1525 static const int cursor_bit_order = BIT_ORDER_MSB;
1527 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1529 struct MouseCursorInfo *cursor;
1530 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1531 int header_lines = 4;
1534 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1536 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1539 for (y = 0; y < cursor->width; y++)
1541 for (x = 0; x < cursor->height; x++)
1544 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1549 cursor->data[i] = cursor->mask[i] = 0;
1552 switch (image[header_lines + y][x])
1555 cursor->data[i] |= bit_mask;
1556 cursor->mask[i] |= bit_mask;
1560 cursor->mask[i] |= bit_mask;
1569 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1574 void SetMouseCursor(int mode)
1576 static struct MouseCursorInfo *cursor_none = NULL;
1577 static struct MouseCursorInfo *cursor_playfield = NULL;
1578 struct MouseCursorInfo *cursor_new;
1579 int mode_final = mode;
1581 if (cursor_none == NULL)
1582 cursor_none = get_cursor_from_image(cursor_image_none);
1584 if (cursor_playfield == NULL)
1585 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1587 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1588 mode_final = gfx.cursor_mode_override;
1590 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1591 mode_final == CURSOR_NONE ? cursor_none :
1592 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1594 SDLSetMouseCursor(cursor_new);
1596 gfx.cursor_mode = mode;
1597 gfx.cursor_mode_final = mode_final;
1600 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1602 // mouse events do not contain logical screen size corrections yet
1603 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1605 mouse_x -= video.screen_xoffset;
1606 mouse_y -= video.screen_yoffset;
1608 gfx.mouse_x = mouse_x;
1609 gfx.mouse_y = mouse_y;
1612 void UpdateMousePosition(void)
1614 int mouse_x, mouse_y;
1617 SDL_GetMouseState(&mouse_x, &mouse_y);
1619 UpdateRawMousePosition(mouse_x, mouse_y);
1623 // ============================================================================
1625 // ============================================================================
1627 void OpenAudio(void)
1629 // always start with reliable default values
1630 audio.sound_available = FALSE;
1631 audio.music_available = FALSE;
1632 audio.loops_available = FALSE;
1634 audio.sound_enabled = FALSE;
1635 audio.sound_deactivated = FALSE;
1637 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1638 audio.mixer_pid = 0;
1639 audio.device_name = NULL;
1640 audio.device_fd = -1;
1642 audio.num_channels = 0;
1643 audio.music_channel = 0;
1644 audio.first_sound_channel = 0;
1649 void CloseAudio(void)
1653 audio.sound_enabled = FALSE;
1656 void SetAudioMode(boolean enabled)
1658 if (!audio.sound_available)
1661 audio.sound_enabled = enabled;
1665 // ============================================================================
1667 // ============================================================================
1669 void InitEventFilter(EventFilter filter_function)
1671 SDL_SetEventFilter(filter_function, NULL);
1674 boolean PendingEvent(void)
1676 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1679 void WaitEvent(Event *event)
1681 SDLWaitEvent(event);
1684 void PeekEvent(Event *event)
1686 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1689 void PumpEvents(void)
1694 void CheckQuitEvent(void)
1696 if (SDL_QuitRequested())
1697 program.exit_function(0);
1700 Key GetEventKey(KeyEvent *event)
1702 // key up/down events in SDL2 do not return text characters anymore
1703 return event->keysym.sym;
1706 KeyMod HandleKeyModState(Key key, int key_status)
1708 static KeyMod current_modifiers = KMOD_None;
1710 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1712 KeyMod new_modifier = KMOD_None;
1717 new_modifier = KMOD_Shift_L;
1720 new_modifier = KMOD_Shift_R;
1722 case KSYM_Control_L:
1723 new_modifier = KMOD_Control_L;
1725 case KSYM_Control_R:
1726 new_modifier = KMOD_Control_R;
1729 new_modifier = KMOD_Meta_L;
1732 new_modifier = KMOD_Meta_R;
1735 new_modifier = KMOD_Alt_L;
1738 new_modifier = KMOD_Alt_R;
1744 if (key_status == KEY_PRESSED)
1745 current_modifiers |= new_modifier;
1747 current_modifiers &= ~new_modifier;
1750 return current_modifiers;
1753 KeyMod GetKeyModState(void)
1755 return (KeyMod)SDL_GetModState();
1758 KeyMod GetKeyModStateFromEvents(void)
1760 /* always use key modifier state as tracked from key events (this is needed
1761 if the modifier key event was injected into the event queue, but the key
1762 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1763 query the keys as held pressed on the keyboard) -- this case is currently
1764 only used to filter out clipboard insert events from "True X-Mouse" tool */
1766 return HandleKeyModState(KSYM_UNDEFINED, 0);
1769 void StartTextInput(int x, int y, int width, int height)
1771 textinput_status = TRUE;
1773 #if defined(HAS_SCREEN_KEYBOARD)
1774 SDL_StartTextInput();
1776 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1778 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1779 video.shifted_up_delay.count = SDL_GetTicks();
1780 video.shifted_up = TRUE;
1785 void StopTextInput(void)
1787 textinput_status = FALSE;
1789 #if defined(HAS_SCREEN_KEYBOARD)
1790 SDL_StopTextInput();
1792 if (video.shifted_up)
1794 video.shifted_up_pos = 0;
1795 video.shifted_up_delay.count = SDL_GetTicks();
1796 video.shifted_up = FALSE;
1801 void PushUserEvent(int code, int value1, int value2)
1805 SDL_memset(&event, 0, sizeof(event));
1807 event.type = EVENT_USER;
1809 event.value1 = value1;
1810 event.value2 = value2;
1812 SDL_PushEvent((SDL_Event *)&event);
1815 boolean PendingEscapeKeyEvent(void)
1821 // check if any key press event is pending
1822 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1825 // check if pressed key is "Escape" key
1826 if (event.key.keysym.sym == KSYM_Escape)
1834 // ============================================================================
1835 // joystick functions
1836 // ============================================================================
1838 void InitJoysticks(void)
1842 #if defined(NO_JOYSTICK)
1843 return; // joysticks generally deactivated by compile-time directive
1846 // always start with reliable default values
1847 joystick.status = JOYSTICK_NOT_AVAILABLE;
1848 for (i = 0; i < MAX_PLAYERS; i++)
1849 joystick.nr[i] = -1; // no joystick configured
1854 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1856 return SDLReadJoystick(nr, x, y, b1, b2);
1859 boolean CheckJoystickOpened(int nr)
1861 return SDLCheckJoystickOpened(nr);
1864 void ClearJoystickState(void)
1866 SDLClearJoystickState();
1870 // ============================================================================
1871 // Emscripten functions
1872 // ============================================================================
1874 void InitEmscriptenFilesystem(void)
1876 #if defined(PLATFORM_EMSCRIPTEN)
1879 dir = UTF8ToString($0);
1881 Module.sync_done = 0;
1883 FS.mkdir(dir); // create persistent data directory
1884 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1885 FS.syncfs(true, function(err) // sync persistent data into memory
1888 Module.sync_done = 1;
1890 }, PERSISTENT_DIRECTORY);
1892 // wait for persistent data to be synchronized to memory
1893 while (emscripten_run_script_int("Module.sync_done") == 0)
1898 void SyncEmscriptenFilesystem(void)
1900 #if defined(PLATFORM_EMSCRIPTEN)
1903 FS.syncfs(function(err)