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 = getLogFilename(getLogBasename(program_basename));
103 program.log_file = program.log_file_default = stdout;
105 program.api_thread_count = 0;
107 program.headless = FALSE;
110 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
111 char *server_host, int server_port)
113 network.enabled = enabled;
114 network.connected = connected;
115 network.serveronly = serveronly;
117 network.server_host = server_host;
118 network.server_port = server_port;
120 network.server_thread = NULL;
121 network.is_server_thread = FALSE;
124 void InitRuntimeInfo()
126 #if defined(HAS_TOUCH_DEVICE)
127 runtime.uses_touch_device = TRUE;
129 runtime.uses_touch_device = FALSE;
132 runtime.use_api_server = setup.use_api_server;
135 void SetWindowTitle(void)
137 program.window_title = program.window_title_function();
142 void InitWindowTitleFunction(char *(*window_title_function)(void))
144 program.window_title_function = window_title_function;
147 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
149 program.exit_message_function = exit_message_function;
152 void InitExitFunction(void (*exit_function)(int))
154 program.exit_function = exit_function;
156 // set signal handlers to custom exit function
157 // signal(SIGINT, exit_function);
158 signal(SIGTERM, exit_function);
160 // set exit function to automatically cleanup SDL stuff after exit()
164 void InitPlatformDependentStuff(void)
166 InitEmscriptenFilesystem();
168 // this is initialized in GetOptions(), but may already be used before
169 options.verbose = TRUE;
173 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
175 if (SDL_Init(sdl_init_flags) < 0)
176 Fail("SDL_Init() failed: %s", SDL_GetError());
181 void ClosePlatformDependentStuff(void)
186 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
187 int real_sx, int real_sy,
188 int full_sxsize, int full_sysize,
189 Bitmap *field_save_buffer)
195 gfx.real_sx = real_sx;
196 gfx.real_sy = real_sy;
197 gfx.full_sxsize = full_sxsize;
198 gfx.full_sysize = full_sysize;
200 gfx.field_save_buffer = field_save_buffer;
202 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
203 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
206 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
208 gfx.game_tile_size = game_tile_size;
209 gfx.standard_tile_size = standard_tile_size;
212 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
220 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
228 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
236 void InitGfxWindowInfo(int win_xsize, int win_ysize)
238 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
240 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
242 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
249 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
252 gfx.win_xsize = win_xsize;
253 gfx.win_ysize = win_ysize;
255 gfx.background_bitmap_mask = REDRAW_NONE;
258 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
260 // currently only used by MSDOS code to alloc VRAM buffer, if available
261 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
262 gfx.scrollbuffer_width = scrollbuffer_width;
263 gfx.scrollbuffer_height = scrollbuffer_height;
266 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
268 gfx.clipping_enabled = enabled;
271 gfx.clip_width = width;
272 gfx.clip_height = height;
275 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean))
277 gfx.draw_busy_anim_function = draw_busy_anim_function;
280 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
282 gfx.draw_global_anim_function = draw_global_anim_function;
285 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
287 gfx.draw_global_border_function = draw_global_border_function;
290 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
292 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
295 void InitGfxDrawEnvelopeRequestFunction(void (*draw_envelope_request_function)(int))
297 gfx.draw_envelope_request_function = draw_envelope_request_function;
300 void InitGfxCustomArtworkInfo(void)
302 gfx.override_level_graphics = FALSE;
303 gfx.override_level_sounds = FALSE;
304 gfx.override_level_music = FALSE;
306 gfx.draw_init_text = TRUE;
309 void InitGfxOtherSettings(void)
311 gfx.cursor_mode = CURSOR_DEFAULT;
312 gfx.cursor_mode_override = CURSOR_UNDEFINED;
313 gfx.cursor_mode_final = gfx.cursor_mode;
315 // prevent initially displaying custom mouse cursor in upper left corner
316 gfx.mouse_x = POS_OFFSCREEN;
317 gfx.mouse_y = POS_OFFSCREEN;
320 void InitTileCursorInfo(void)
322 tile_cursor.enabled = FALSE;
323 tile_cursor.active = FALSE;
324 tile_cursor.moving = FALSE;
326 tile_cursor.xpos = 0;
327 tile_cursor.ypos = 0;
330 tile_cursor.target_x = 0;
331 tile_cursor.target_y = 0;
336 tile_cursor.xsn_debug = FALSE;
339 void InitOverlayInfo(void)
341 overlay.enabled = FALSE;
342 overlay.active = FALSE;
344 overlay.show_grid = FALSE;
346 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
347 overlay.grid_button_action = JOY_NO_ACTION;
349 SetOverlayGridSizeAndButtons();
351 #if defined(USE_TOUCH_INPUT_OVERLAY)
352 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
353 overlay.enabled = TRUE;
357 void SetOverlayGridSizeAndButtons(void)
359 int nr = GRID_ACTIVE_NR();
362 overlay.grid_xsize = setup.touch.grid_xsize[nr];
363 overlay.grid_ysize = setup.touch.grid_ysize[nr];
365 for (x = 0; x < MAX_GRID_XSIZE; x++)
366 for (y = 0; y < MAX_GRID_YSIZE; y++)
367 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
370 void SetTileCursorEnabled(boolean enabled)
372 tile_cursor.enabled = enabled;
375 void SetTileCursorActive(boolean active)
377 tile_cursor.active = active;
380 void SetTileCursorTargetXY(int x, int y)
382 // delayed placement of tile selection cursor at target position
383 // (tile cursor will be moved to target position step by step)
385 tile_cursor.xpos = x;
386 tile_cursor.ypos = y;
387 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
388 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
390 tile_cursor.moving = TRUE;
393 void SetTileCursorXY(int x, int y)
395 // immediate placement of tile selection cursor at target position
397 SetTileCursorTargetXY(x, y);
399 tile_cursor.x = tile_cursor.target_x;
400 tile_cursor.y = tile_cursor.target_y;
402 tile_cursor.moving = FALSE;
405 void SetTileCursorSXSY(int sx, int sy)
411 void SetOverlayEnabled(boolean enabled)
413 overlay.enabled = enabled;
416 void SetOverlayActive(boolean active)
418 overlay.active = active;
421 void SetOverlayShowGrid(boolean show_grid)
423 overlay.show_grid = show_grid;
425 SetOverlayActive(show_grid);
428 SetOverlayEnabled(TRUE);
431 boolean GetOverlayEnabled(void)
433 return overlay.enabled;
436 boolean GetOverlayActive(void)
438 return overlay.active;
441 void SetDrawDeactivationMask(int draw_deactivation_mask)
443 gfx.draw_deactivation_mask = draw_deactivation_mask;
446 int GetDrawDeactivationMask(void)
448 return gfx.draw_deactivation_mask;
451 void SetDrawBackgroundMask(int draw_background_mask)
453 gfx.draw_background_mask = draw_background_mask;
456 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask,
457 int x, int y, int width, int height)
459 if (background_bitmap_tile != NULL)
460 gfx.background_bitmap_mask |= mask;
462 gfx.background_bitmap_mask &= ~mask;
464 if (background_bitmap_tile == NULL) // empty background requested
467 if (mask == REDRAW_ALL)
468 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
470 0, 0, video.width, video.height);
471 else if (mask == REDRAW_FIELD)
472 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
474 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
475 else if (mask == REDRAW_DOOR_1)
476 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
478 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
482 // ============================================================================
484 // ============================================================================
486 static int GetRealDepth(int depth)
488 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
491 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
492 int width, int height, Pixel color)
494 SDLFillRectangle(bitmap, x, y, width, height, color);
496 if (bitmap == backbuffer)
497 SetRedrawMaskFromArea(x, y, width, height);
500 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
501 int src_x, int src_y, int width, int height,
502 int dst_x, int dst_y, int mask_mode)
504 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
505 dst_x, dst_y, mask_mode);
507 if (dst_bitmap == backbuffer)
508 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
511 void LimitScreenUpdates(boolean enable)
513 SDLLimitScreenUpdates(enable);
516 void InitVideoDefaults(void)
518 video.default_depth = 32;
521 void InitVideoDisplay(void)
523 if (program.headless)
526 SDLInitVideoDisplay();
530 void CloseVideoDisplay(void)
532 KeyboardAutoRepeatOn();
534 SDL_QuitSubSystem(SDL_INIT_VIDEO);
537 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
540 video.height = height;
541 video.depth = GetRealDepth(depth);
543 video.screen_width = width;
544 video.screen_height = height;
545 video.screen_xoffset = 0;
546 video.screen_yoffset = 0;
548 video.fullscreen_available = FULLSCREEN_STATUS;
549 video.fullscreen_enabled = FALSE;
551 video.window_scaling_available = WINDOW_SCALING_STATUS;
553 video.frame_counter = 0;
554 video.frame_delay.count = 0;
555 video.frame_delay.value = GAME_FRAME_DELAY;
557 video.shifted_up = FALSE;
558 video.shifted_up_pos = 0;
559 video.shifted_up_pos_last = 0;
560 video.shifted_up_delay.count = 0;
561 video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
563 SDLInitVideoBuffer(fullscreen);
565 video.initialized = !program.headless;
570 static void FreeBitmapPointers(Bitmap *bitmap)
575 SDLFreeBitmapPointers(bitmap);
577 checked_free(bitmap->source_filename);
578 bitmap->source_filename = NULL;
581 static void TransferBitmapPointers(Bitmap *src_bitmap,
584 if (src_bitmap == NULL || dst_bitmap == NULL)
587 FreeBitmapPointers(dst_bitmap);
589 *dst_bitmap = *src_bitmap;
592 void FreeBitmap(Bitmap *bitmap)
597 FreeBitmapPointers(bitmap);
602 Bitmap *CreateBitmapStruct(void)
604 return checked_calloc(sizeof(Bitmap));
607 Bitmap *CreateBitmap(int width, int height, int depth)
609 Bitmap *new_bitmap = CreateBitmapStruct();
610 int real_width = MAX(1, width); // prevent zero bitmap width
611 int real_height = MAX(1, height); // prevent zero bitmap height
612 int real_depth = GetRealDepth(depth);
614 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
616 new_bitmap->width = real_width;
617 new_bitmap->height = real_height;
622 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
626 // if new bitmap size fits into old one, no need to re-create it
627 if (width <= (*bitmap)->width &&
628 height <= (*bitmap)->height)
631 // else adjust size so that old and new bitmap size fit into it
632 width = MAX(width, (*bitmap)->width);
633 height = MAX(height, (*bitmap)->height);
636 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
640 *bitmap = new_bitmap;
644 TransferBitmapPointers(new_bitmap, *bitmap);
650 static void CloseWindow(DrawWindow *window)
655 void SetRedrawMaskFromArea(int x, int y, int width, int height)
659 int x2 = x + width - 1;
660 int y2 = y + height - 1;
662 if (width == 0 || height == 0)
665 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
666 redraw_mask |= REDRAW_FIELD;
667 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
668 redraw_mask |= REDRAW_DOOR_1;
669 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
670 redraw_mask |= REDRAW_DOOR_2;
671 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
672 redraw_mask |= REDRAW_DOOR_3;
674 redraw_mask = REDRAW_ALL;
677 static boolean CheckDrawingArea(int x, int y, int draw_mask)
679 if (draw_mask == REDRAW_NONE)
682 if (draw_mask & REDRAW_ALL)
685 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
688 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
691 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
694 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
700 boolean DrawingDeactivatedField(void)
702 if (program.headless)
705 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
711 boolean DrawingDeactivated(int x, int y)
713 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
716 boolean DrawingOnBackground(int x, int y)
718 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
719 CheckDrawingArea(x, y, gfx.draw_background_mask));
722 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
723 int *width, int *height, boolean is_dest)
725 int clip_x, clip_y, clip_width, clip_height;
727 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
729 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
730 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
731 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
732 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
738 clip_width = bitmap->width;
739 clip_height = bitmap->height;
742 // skip if rectangle completely outside bitmap
744 if (*x + *width <= clip_x ||
745 *y + *height <= clip_y ||
746 *x >= clip_x + clip_width ||
747 *y >= clip_y + clip_height)
750 // clip if rectangle overlaps bitmap
754 *width -= clip_x - *x;
757 else if (*x + *width > clip_x + clip_width)
759 *width = clip_x + clip_width - *x;
764 *height -= clip_y - *y;
767 else if (*y + *height > clip_y + clip_height)
769 *height = clip_y + clip_height - *y;
775 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
776 int src_x, int src_y, int width, int height,
777 int dst_x, int dst_y)
779 int dst_x_unclipped = dst_x;
780 int dst_y_unclipped = dst_y;
782 if (program.headless)
785 if (src_bitmap == NULL || dst_bitmap == NULL)
788 if (DrawingDeactivated(dst_x, dst_y))
791 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
792 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
795 // source x/y might need adjustment if destination x/y was clipped top/left
796 src_x += dst_x - dst_x_unclipped;
797 src_y += dst_y - dst_y_unclipped;
799 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
800 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
801 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
802 but is already fixed in SVN and should therefore finally be fixed with
803 the next official SDL release, which is probably version 1.2.14.) */
804 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
806 if (src_bitmap == dst_bitmap)
808 // needed when blitting directly to same bitmap -- should not be needed with
809 // recent SDL libraries, but apparently does not work in 1.2.11 directly
811 static Bitmap *tmp_bitmap = NULL;
812 static int tmp_bitmap_xsize = 0;
813 static int tmp_bitmap_ysize = 0;
815 // start with largest static bitmaps for initial bitmap size ...
816 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
818 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
819 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
822 // ... and allow for later re-adjustments due to custom artwork bitmaps
823 if (src_bitmap->width > tmp_bitmap_xsize ||
824 src_bitmap->height > tmp_bitmap_ysize)
826 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
827 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
829 FreeBitmap(tmp_bitmap);
834 if (tmp_bitmap == NULL)
835 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
838 sysCopyArea(src_bitmap, tmp_bitmap,
839 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
840 sysCopyArea(tmp_bitmap, dst_bitmap,
841 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
846 sysCopyArea(src_bitmap, dst_bitmap,
847 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
850 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
851 int src_x, int src_y, int src_width, int src_height,
852 int dst_x, int dst_y, int dst_width, int dst_height)
854 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
855 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
856 int dst_xsize = dst_width;
857 int dst_ysize = dst_height;
858 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
859 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
862 for (y = 0; y < src_ysteps; y++)
864 for (x = 0; x < src_xsteps; x++)
866 int draw_x = dst_x + x * src_xsize;
867 int draw_y = dst_y + y * src_ysize;
868 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
869 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
871 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
877 void FadeRectangle(int x, int y, int width, int height,
878 int fade_mode, int fade_delay, int post_delay,
879 void (*draw_border_function)(void))
881 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
882 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
885 SDLFadeRectangle(x, y, width, height,
886 fade_mode, fade_delay, post_delay, draw_border_function);
889 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
892 if (program.headless)
895 if (DrawingDeactivated(x, y))
898 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
901 sysFillRectangle(bitmap, x, y, width, height, color);
904 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
906 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
909 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
910 int width, int height)
912 if (DrawingOnBackground(x, y))
913 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
915 ClearRectangle(bitmap, x, y, width, height);
918 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
919 int src_x, int src_y, int width, int height,
920 int dst_x, int dst_y)
922 if (DrawingDeactivated(dst_x, dst_y))
925 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
926 dst_x, dst_y, BLIT_MASKED);
929 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
930 int src_x, int src_y, int width, int height,
931 int dst_x, int dst_y)
933 if (DrawingOnBackground(dst_x, dst_y))
936 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
940 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
944 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
948 void BlitTexture(Bitmap *bitmap,
949 int src_x, int src_y, int width, int height,
950 int dst_x, int dst_y)
955 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
959 void BlitTextureMasked(Bitmap *bitmap,
960 int src_x, int src_y, int width, int height,
961 int dst_x, int dst_y)
966 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
970 void BlitToScreen(Bitmap *bitmap,
971 int src_x, int src_y, int width, int height,
972 int dst_x, int dst_y)
977 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
978 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
979 width, height, dst_x, dst_y);
981 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
984 void BlitToScreenMasked(Bitmap *bitmap,
985 int src_x, int src_y, int width, int height,
986 int dst_x, int dst_y)
991 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
992 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
993 width, height, dst_x, dst_y);
995 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
998 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1001 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1004 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1005 int to_x, int to_y, Pixel pixel, int line_width)
1009 if (program.headless)
1012 for (x = 0; x < line_width; x++)
1014 for (y = 0; y < line_width; y++)
1016 int dx = x - line_width / 2;
1017 int dy = y - line_width / 2;
1019 if ((x == 0 && y == 0) ||
1020 (x == 0 && y == line_width - 1) ||
1021 (x == line_width - 1 && y == 0) ||
1022 (x == line_width - 1 && y == line_width - 1))
1026 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1031 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1036 for (i = 0; i < num_points - 1; i++)
1037 DrawLine(bitmap, points[i].x, points[i].y,
1038 points[i + 1].x, points[i + 1].y, pixel, line_width);
1041 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1045 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1047 if (program.headless)
1050 if (x < 0 || x >= bitmap->width ||
1051 y < 0 || y >= bitmap->height)
1054 return SDLGetPixel(bitmap, x, y);
1057 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1058 unsigned int color_g, unsigned int color_b)
1060 if (program.headless)
1063 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1066 void KeyboardAutoRepeatOn(void)
1068 keyrepeat_status = TRUE;
1071 void KeyboardAutoRepeatOff(void)
1073 keyrepeat_status = FALSE;
1076 boolean SetVideoMode(boolean fullscreen)
1078 return SDLSetVideoMode(fullscreen);
1081 void SetVideoFrameDelay(unsigned int frame_delay_value)
1083 video.frame_delay.value = frame_delay_value;
1086 unsigned int GetVideoFrameDelay(void)
1088 return video.frame_delay.value;
1091 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1093 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1094 (!fullscreen && video.fullscreen_enabled))
1095 fullscreen = SetVideoMode(fullscreen);
1100 Bitmap *LoadImage(char *filename)
1104 new_bitmap = SDLLoadImage(filename);
1107 new_bitmap->source_filename = getStringCopy(filename);
1112 Bitmap *LoadCustomImage(char *basename)
1114 char *filename = getCustomImageFilename(basename);
1117 if (filename == NULL)
1118 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1120 if ((new_bitmap = LoadImage(filename)) == NULL)
1121 Fail("LoadImage('%s') failed", basename);
1126 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1128 char *filename = getCustomImageFilename(basename);
1131 if (filename == NULL) // (should never happen)
1133 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1138 if (strEqual(filename, bitmap->source_filename))
1140 // The old and new image are the same (have the same filename and path).
1141 // This usually means that this image does not exist in this graphic set
1142 // and a fallback to the existing image is done.
1147 if ((new_bitmap = LoadImage(filename)) == NULL)
1149 Warn("LoadImage('%s') failed", basename);
1154 if (bitmap->width != new_bitmap->width ||
1155 bitmap->height != new_bitmap->height)
1157 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1160 FreeBitmap(new_bitmap);
1165 TransferBitmapPointers(new_bitmap, bitmap);
1169 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1171 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1174 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1176 if (bitmaps[IMG_BITMAP_CUSTOM])
1178 // check if original sized bitmap points to custom sized bitmap
1179 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1181 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1183 // keep pointer of previous custom size bitmap
1184 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1186 // set original bitmap pointer to scaled original bitmap of other size
1187 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1189 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1193 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1196 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1199 if (gfx.game_tile_size == gfx.standard_tile_size)
1201 // set game bitmap pointer to standard sized bitmap (already existing)
1202 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1207 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1208 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1209 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1211 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1213 // set game bitmap pointer to custom sized bitmap (newly created)
1214 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1217 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1218 int tile_size, boolean create_small_bitmaps)
1220 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1221 Bitmap *tmp_bitmap_final = NULL;
1222 Bitmap *tmp_bitmap_0 = NULL;
1223 Bitmap *tmp_bitmap_1 = NULL;
1224 Bitmap *tmp_bitmap_2 = NULL;
1225 Bitmap *tmp_bitmap_4 = NULL;
1226 Bitmap *tmp_bitmap_8 = NULL;
1227 Bitmap *tmp_bitmap_16 = NULL;
1228 Bitmap *tmp_bitmap_32 = NULL;
1229 int width_final, height_final;
1230 int width_0, height_0;
1231 int width_1, height_1;
1232 int width_2, height_2;
1233 int width_4, height_4;
1234 int width_8, height_8;
1235 int width_16, height_16;
1236 int width_32, height_32;
1237 int old_width, old_height;
1240 print_timestamp_init("CreateScaledBitmaps");
1242 old_width = old_bitmap->width;
1243 old_height = old_bitmap->height;
1245 // calculate new image dimensions for final image size
1246 width_final = old_width * zoom_factor;
1247 height_final = old_height * zoom_factor;
1249 // get image with final size (this might require scaling up)
1250 // ("final" size may result in non-standard tile size image)
1251 if (zoom_factor != 1)
1252 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1254 tmp_bitmap_final = old_bitmap;
1256 UPDATE_BUSY_STATE();
1258 width_0 = width_1 = width_final;
1259 height_0 = height_1 = height_final;
1261 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1263 if (create_small_bitmaps)
1265 // check if we have a non-gameplay tile size image
1266 if (tile_size != gfx.game_tile_size)
1268 // get image with gameplay tile size
1269 width_0 = width_final * gfx.game_tile_size / tile_size;
1270 height_0 = height_final * gfx.game_tile_size / tile_size;
1272 if (width_0 == old_width)
1273 tmp_bitmap_0 = old_bitmap;
1274 else if (width_0 == width_final)
1275 tmp_bitmap_0 = tmp_bitmap_final;
1277 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1279 UPDATE_BUSY_STATE();
1282 // check if we have a non-standard tile size image
1283 if (tile_size != gfx.standard_tile_size)
1285 // get image with standard tile size
1286 width_1 = width_final * gfx.standard_tile_size / tile_size;
1287 height_1 = height_final * gfx.standard_tile_size / tile_size;
1289 if (width_1 == old_width)
1290 tmp_bitmap_1 = old_bitmap;
1291 else if (width_1 == width_final)
1292 tmp_bitmap_1 = tmp_bitmap_final;
1293 else if (width_1 == width_0)
1294 tmp_bitmap_1 = tmp_bitmap_0;
1296 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1298 UPDATE_BUSY_STATE();
1301 // calculate new image dimensions for small images
1302 width_2 = width_1 / 2;
1303 height_2 = height_1 / 2;
1304 width_4 = width_1 / 4;
1305 height_4 = height_1 / 4;
1306 width_8 = width_1 / 8;
1307 height_8 = height_1 / 8;
1308 width_16 = width_1 / 16;
1309 height_16 = height_1 / 16;
1310 width_32 = width_1 / 32;
1311 height_32 = height_1 / 32;
1313 // get image with 1/2 of normal size (for use in the level editor)
1314 if (width_2 == old_width)
1315 tmp_bitmap_2 = old_bitmap;
1317 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1319 UPDATE_BUSY_STATE();
1321 // get image with 1/4 of normal size (for use in the level editor)
1322 if (width_4 == old_width)
1323 tmp_bitmap_4 = old_bitmap;
1325 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1327 UPDATE_BUSY_STATE();
1329 // get image with 1/8 of normal size (for use on the preview screen)
1330 if (width_8 == old_width)
1331 tmp_bitmap_8 = old_bitmap;
1333 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1335 UPDATE_BUSY_STATE();
1337 // get image with 1/16 of normal size (for use on the preview screen)
1338 if (width_16 == old_width)
1339 tmp_bitmap_16 = old_bitmap;
1341 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1343 UPDATE_BUSY_STATE();
1345 // get image with 1/32 of normal size (for use on the preview screen)
1346 if (width_32 == old_width)
1347 tmp_bitmap_32 = old_bitmap;
1349 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1351 UPDATE_BUSY_STATE();
1353 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1354 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1355 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1356 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1357 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1358 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1360 if (width_0 != width_1)
1361 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1363 if (bitmaps[IMG_BITMAP_CUSTOM])
1364 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1366 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1368 // store the "final" (up-scaled) original bitmap, if not already stored
1370 int tmp_bitmap_final_nr = -1;
1372 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1373 if (bitmaps[i] == tmp_bitmap_final)
1374 tmp_bitmap_final_nr = i;
1376 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1378 // store pointer of scaled original bitmap (not used for any other size)
1379 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1381 // set original bitmap pointer to scaled original bitmap of other size
1382 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1386 // set original bitmap pointer to corresponding sized bitmap
1387 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1390 // free the "old" (unscaled) original bitmap, if not already stored
1392 boolean free_old_bitmap = TRUE;
1394 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1395 if (bitmaps[i] == old_bitmap)
1396 free_old_bitmap = FALSE;
1398 if (free_old_bitmap)
1400 // copy image filename from old to new standard sized bitmap
1401 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1402 getStringCopy(old_bitmap->source_filename);
1404 FreeBitmap(old_bitmap);
1409 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1411 // set original bitmap pointer to corresponding sized bitmap
1412 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1414 if (old_bitmap != tmp_bitmap_1)
1415 FreeBitmap(old_bitmap);
1418 UPDATE_BUSY_STATE();
1420 print_timestamp_done("CreateScaledBitmaps");
1423 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1426 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1429 void CreateBitmapTextures(Bitmap **bitmaps)
1431 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1432 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1434 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1437 void FreeBitmapTextures(Bitmap **bitmaps)
1439 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1440 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1442 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1445 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1447 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1451 // ----------------------------------------------------------------------------
1452 // mouse pointer functions
1453 // ----------------------------------------------------------------------------
1455 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1457 // XPM image definitions
1458 static const char *cursor_image_none[] =
1460 // width height num_colors chars_per_pixel
1490 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1491 static const char *cursor_image_dot[] =
1493 // width height num_colors chars_per_pixel
1522 static const char **cursor_image_playfield = cursor_image_dot;
1524 // some people complained about a "white dot" on the screen and thought it
1525 // was a graphical error... OK, let's just remove the whole pointer :-)
1526 static const char **cursor_image_playfield = cursor_image_none;
1529 static const int cursor_bit_order = BIT_ORDER_MSB;
1531 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1533 struct MouseCursorInfo *cursor;
1534 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1535 int header_lines = 4;
1538 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1540 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1543 for (y = 0; y < cursor->width; y++)
1545 for (x = 0; x < cursor->height; x++)
1548 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1553 cursor->data[i] = cursor->mask[i] = 0;
1556 switch (image[header_lines + y][x])
1559 cursor->data[i] |= bit_mask;
1560 cursor->mask[i] |= bit_mask;
1564 cursor->mask[i] |= bit_mask;
1573 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1578 void SetMouseCursor(int mode)
1580 static struct MouseCursorInfo *cursor_none = NULL;
1581 static struct MouseCursorInfo *cursor_playfield = NULL;
1582 struct MouseCursorInfo *cursor_new;
1583 int mode_final = mode;
1585 if (cursor_none == NULL)
1586 cursor_none = get_cursor_from_image(cursor_image_none);
1588 if (cursor_playfield == NULL)
1589 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1591 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1592 mode_final = gfx.cursor_mode_override;
1594 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1595 mode_final == CURSOR_NONE ? cursor_none :
1596 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1598 SDLSetMouseCursor(cursor_new);
1600 gfx.cursor_mode = mode;
1601 gfx.cursor_mode_final = mode_final;
1604 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1606 // mouse events do not contain logical screen size corrections yet
1607 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1609 mouse_x -= video.screen_xoffset;
1610 mouse_y -= video.screen_yoffset;
1612 gfx.mouse_x = mouse_x;
1613 gfx.mouse_y = mouse_y;
1616 void UpdateMousePosition(void)
1618 int mouse_x, mouse_y;
1621 SDL_GetMouseState(&mouse_x, &mouse_y);
1623 UpdateRawMousePosition(mouse_x, mouse_y);
1627 // ============================================================================
1629 // ============================================================================
1631 void OpenAudio(void)
1633 // always start with reliable default values
1634 audio.sound_available = FALSE;
1635 audio.music_available = FALSE;
1636 audio.loops_available = FALSE;
1638 audio.sound_enabled = FALSE;
1639 audio.sound_deactivated = FALSE;
1641 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1642 audio.mixer_pid = 0;
1643 audio.device_name = NULL;
1644 audio.device_fd = -1;
1646 audio.num_channels = 0;
1647 audio.music_channel = 0;
1648 audio.first_sound_channel = 0;
1653 void CloseAudio(void)
1657 audio.sound_enabled = FALSE;
1660 void SetAudioMode(boolean enabled)
1662 if (!audio.sound_available)
1665 audio.sound_enabled = enabled;
1669 // ============================================================================
1671 // ============================================================================
1673 void InitEventFilter(EventFilter filter_function)
1675 SDL_SetEventFilter(filter_function, NULL);
1678 boolean PendingEvent(void)
1680 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1683 void WaitEvent(Event *event)
1685 SDLWaitEvent(event);
1688 void PeekEvent(Event *event)
1690 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1693 void PumpEvents(void)
1698 void CheckQuitEvent(void)
1700 if (SDL_QuitRequested())
1701 program.exit_function(0);
1704 Key GetEventKey(KeyEvent *event)
1706 // key up/down events in SDL2 do not return text characters anymore
1707 return event->keysym.sym;
1710 KeyMod HandleKeyModState(Key key, int key_status)
1712 static KeyMod current_modifiers = KMOD_None;
1714 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1716 KeyMod new_modifier = KMOD_None;
1721 new_modifier = KMOD_Shift_L;
1724 new_modifier = KMOD_Shift_R;
1726 case KSYM_Control_L:
1727 new_modifier = KMOD_Control_L;
1729 case KSYM_Control_R:
1730 new_modifier = KMOD_Control_R;
1733 new_modifier = KMOD_Meta_L;
1736 new_modifier = KMOD_Meta_R;
1739 new_modifier = KMOD_Alt_L;
1742 new_modifier = KMOD_Alt_R;
1748 if (key_status == KEY_PRESSED)
1749 current_modifiers |= new_modifier;
1751 current_modifiers &= ~new_modifier;
1754 return current_modifiers;
1757 KeyMod GetKeyModState(void)
1759 return (KeyMod)SDL_GetModState();
1762 KeyMod GetKeyModStateFromEvents(void)
1764 /* always use key modifier state as tracked from key events (this is needed
1765 if the modifier key event was injected into the event queue, but the key
1766 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1767 query the keys as held pressed on the keyboard) -- this case is currently
1768 only used to filter out clipboard insert events from "True X-Mouse" tool */
1770 return HandleKeyModState(KSYM_UNDEFINED, 0);
1773 void StartTextInput(int x, int y, int width, int height)
1775 textinput_status = TRUE;
1777 #if defined(HAS_SCREEN_KEYBOARD)
1778 SDL_StartTextInput();
1780 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1782 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1783 video.shifted_up_delay.count = SDL_GetTicks();
1784 video.shifted_up = TRUE;
1789 void StopTextInput(void)
1791 textinput_status = FALSE;
1793 #if defined(HAS_SCREEN_KEYBOARD)
1794 SDL_StopTextInput();
1796 if (video.shifted_up)
1798 video.shifted_up_pos = 0;
1799 video.shifted_up_delay.count = SDL_GetTicks();
1800 video.shifted_up = FALSE;
1805 void PushUserEvent(int code, int value1, int value2)
1809 SDL_memset(&event, 0, sizeof(event));
1811 event.type = EVENT_USER;
1813 event.value1 = value1;
1814 event.value2 = value2;
1816 SDL_PushEvent((SDL_Event *)&event);
1819 boolean PendingEscapeKeyEvent(void)
1825 // check if any key press event is pending
1826 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1829 // check if pressed key is "Escape" key
1830 if (event.key.keysym.sym == KSYM_Escape)
1838 // ============================================================================
1839 // joystick functions
1840 // ============================================================================
1842 void InitJoysticks(void)
1846 #if defined(NO_JOYSTICK)
1847 return; // joysticks generally deactivated by compile-time directive
1850 // always start with reliable default values
1851 joystick.status = JOYSTICK_NOT_AVAILABLE;
1852 for (i = 0; i < MAX_PLAYERS; i++)
1853 joystick.nr[i] = -1; // no joystick configured
1858 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1860 return SDLReadJoystick(nr, x, y, b1, b2);
1863 boolean CheckJoystickOpened(int nr)
1865 return SDLCheckJoystickOpened(nr);
1868 void ClearJoystickState(void)
1870 SDLClearJoystickState();
1874 // ============================================================================
1875 // Emscripten functions
1876 // ============================================================================
1878 void InitEmscriptenFilesystem(void)
1880 #if defined(PLATFORM_EMSCRIPTEN)
1883 dir = UTF8ToString($0);
1885 Module.sync_done = 0;
1887 FS.mkdir(dir); // create persistent data directory
1888 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1889 FS.syncfs(true, function(err) // sync persistent data into memory
1892 Module.sync_done = 1;
1894 }, PERSISTENT_DIRECTORY);
1896 // wait for persistent data to be synchronized to memory
1897 while (emscripten_run_script_int("Module.sync_done") == 0)
1902 void SyncEmscriptenFilesystem(void)
1904 #if defined(PLATFORM_EMSCRIPTEN)
1907 FS.syncfs(function(err)