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(void)
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, 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 void ResetBitmapAlpha(Bitmap *bitmap)
604 bitmap->alpha[0][0] = -1;
605 bitmap->alpha[0][1] = -1;
606 bitmap->alpha[1][0] = -1;
607 bitmap->alpha[1][1] = -1;
608 bitmap->alpha_next_blit = -1;
611 Bitmap *CreateBitmapStruct(void)
613 Bitmap *new_bitmap = checked_calloc(sizeof(Bitmap));
615 ResetBitmapAlpha(new_bitmap);
620 Bitmap *CreateBitmap(int width, int height, int depth)
622 Bitmap *new_bitmap = CreateBitmapStruct();
623 int real_width = MAX(1, width); // prevent zero bitmap width
624 int real_height = MAX(1, height); // prevent zero bitmap height
625 int real_depth = GetRealDepth(depth);
627 new_bitmap->surface = SDLCreateNativeSurface(real_width, real_height, real_depth);
629 new_bitmap->width = real_width;
630 new_bitmap->height = real_height;
635 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
639 // if new bitmap size fits into old one, no need to re-create it
640 if (width <= (*bitmap)->width &&
641 height <= (*bitmap)->height)
644 // else adjust size so that old and new bitmap size fit into it
645 width = MAX(width, (*bitmap)->width);
646 height = MAX(height, (*bitmap)->height);
649 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
653 *bitmap = new_bitmap;
657 TransferBitmapPointers(new_bitmap, *bitmap);
663 static void CloseWindow(DrawWindow *window)
668 void SetRedrawMaskFromArea(int x, int y, int width, int height)
672 int x2 = x + width - 1;
673 int y2 = y + height - 1;
675 if (width == 0 || height == 0)
678 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
679 redraw_mask |= REDRAW_FIELD;
680 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
681 redraw_mask |= REDRAW_DOOR_1;
682 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
683 redraw_mask |= REDRAW_DOOR_2;
684 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
685 redraw_mask |= REDRAW_DOOR_3;
687 redraw_mask = REDRAW_ALL;
690 static boolean CheckDrawingArea(int x, int y, int draw_mask)
692 if (draw_mask == REDRAW_NONE)
695 if (draw_mask & REDRAW_ALL)
698 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
701 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
704 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
707 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
713 boolean DrawingDeactivatedField(void)
715 if (program.headless)
718 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
724 boolean DrawingDeactivated(int x, int y)
726 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
729 boolean DrawingOnBackground(int x, int y)
731 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
732 CheckDrawingArea(x, y, gfx.draw_background_mask));
735 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
736 int *width, int *height, boolean is_dest)
738 int clip_x, clip_y, clip_width, clip_height;
740 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
742 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
743 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
744 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
745 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
751 clip_width = bitmap->width;
752 clip_height = bitmap->height;
755 // skip if rectangle completely outside bitmap
757 if (*x + *width <= clip_x ||
758 *y + *height <= clip_y ||
759 *x >= clip_x + clip_width ||
760 *y >= clip_y + clip_height)
763 // clip if rectangle overlaps bitmap
767 *width -= clip_x - *x;
770 else if (*x + *width > clip_x + clip_width)
772 *width = clip_x + clip_width - *x;
777 *height -= clip_y - *y;
780 else if (*y + *height > clip_y + clip_height)
782 *height = clip_y + clip_height - *y;
788 void SetBitmapAlphaNextBlit(Bitmap *bitmap, int alpha)
790 // set alpha value for next blitting of bitmap
791 bitmap->alpha_next_blit = alpha;
794 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
795 int src_x, int src_y, int width, int height,
796 int dst_x, int dst_y)
798 int dst_x_unclipped = dst_x;
799 int dst_y_unclipped = dst_y;
801 if (program.headless)
804 if (src_bitmap == NULL || dst_bitmap == NULL)
807 if (DrawingDeactivated(dst_x, dst_y))
810 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
811 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
814 // source x/y might need adjustment if destination x/y was clipped top/left
815 src_x += dst_x - dst_x_unclipped;
816 src_y += dst_y - dst_y_unclipped;
818 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
819 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
820 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
821 but is already fixed in SVN and should therefore finally be fixed with
822 the next official SDL release, which is probably version 1.2.14.) */
823 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
825 if (src_bitmap == dst_bitmap)
827 // needed when blitting directly to same bitmap -- should not be needed with
828 // recent SDL libraries, but apparently does not work in 1.2.11 directly
830 static Bitmap *tmp_bitmap = NULL;
831 static int tmp_bitmap_xsize = 0;
832 static int tmp_bitmap_ysize = 0;
834 // start with largest static bitmaps for initial bitmap size ...
835 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
837 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
838 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
841 // ... and allow for later re-adjustments due to custom artwork bitmaps
842 if (src_bitmap->width > tmp_bitmap_xsize ||
843 src_bitmap->height > tmp_bitmap_ysize)
845 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
846 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
848 FreeBitmap(tmp_bitmap);
853 if (tmp_bitmap == NULL)
854 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
857 sysCopyArea(src_bitmap, tmp_bitmap,
858 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
859 sysCopyArea(tmp_bitmap, dst_bitmap,
860 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
865 sysCopyArea(src_bitmap, dst_bitmap,
866 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
869 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
870 int src_x, int src_y, int src_width, int src_height,
871 int dst_x, int dst_y, int dst_width, int dst_height)
873 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
874 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
875 int dst_xsize = dst_width;
876 int dst_ysize = dst_height;
877 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
878 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
881 for (y = 0; y < src_ysteps; y++)
883 for (x = 0; x < src_xsteps; x++)
885 int draw_x = dst_x + x * src_xsize;
886 int draw_y = dst_y + y * src_ysize;
887 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
888 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
890 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
896 void FadeRectangle(int x, int y, int width, int height,
897 int fade_mode, int fade_delay, int post_delay,
898 void (*draw_border_function)(void))
900 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
901 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
904 SDLFadeRectangle(x, y, width, height,
905 fade_mode, fade_delay, post_delay, draw_border_function);
908 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
911 if (program.headless)
914 if (DrawingDeactivated(x, y))
917 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
920 sysFillRectangle(bitmap, x, y, width, height, color);
923 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
925 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
928 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
929 int width, int height)
931 if (DrawingOnBackground(x, y))
932 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
934 ClearRectangle(bitmap, x, y, width, height);
937 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
938 int src_x, int src_y, int width, int height,
939 int dst_x, int dst_y)
941 if (program.headless)
944 if (src_bitmap == NULL || dst_bitmap == NULL)
947 if (DrawingDeactivated(dst_x, dst_y))
950 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
951 dst_x, dst_y, BLIT_MASKED);
954 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
955 int src_x, int src_y, int width, int height,
956 int dst_x, int dst_y)
958 if (DrawingOnBackground(dst_x, dst_y))
961 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
965 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
969 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
973 void BlitTexture(Bitmap *bitmap,
974 int src_x, int src_y, int width, int height,
975 int dst_x, int dst_y)
980 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
984 void BlitTextureMasked(Bitmap *bitmap,
985 int src_x, int src_y, int width, int height,
986 int dst_x, int dst_y)
991 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
995 void BlitToScreen(Bitmap *bitmap,
996 int src_x, int src_y, int width, int height,
997 int dst_x, int dst_y)
1002 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1003 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1004 width, height, dst_x, dst_y);
1006 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1009 void BlitToScreenMasked(Bitmap *bitmap,
1010 int src_x, int src_y, int width, int height,
1011 int dst_x, int dst_y)
1016 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1017 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1018 width, height, dst_x, dst_y);
1020 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1023 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1026 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1029 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1030 int to_x, int to_y, Pixel pixel, int line_width)
1034 if (program.headless)
1037 for (x = 0; x < line_width; x++)
1039 for (y = 0; y < line_width; y++)
1041 int dx = x - line_width / 2;
1042 int dy = y - line_width / 2;
1044 if ((x == 0 && y == 0) ||
1045 (x == 0 && y == line_width - 1) ||
1046 (x == line_width - 1 && y == 0) ||
1047 (x == line_width - 1 && y == line_width - 1))
1051 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1056 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1061 for (i = 0; i < num_points - 1; i++)
1062 DrawLine(bitmap, points[i].x, points[i].y,
1063 points[i + 1].x, points[i + 1].y, pixel, line_width);
1066 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1070 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1072 if (program.headless)
1075 if (x < 0 || x >= bitmap->width ||
1076 y < 0 || y >= bitmap->height)
1079 return SDLGetPixel(bitmap, x, y);
1082 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1083 unsigned int color_g, unsigned int color_b)
1085 if (program.headless)
1088 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1091 void KeyboardAutoRepeatOn(void)
1093 keyrepeat_status = TRUE;
1096 void KeyboardAutoRepeatOff(void)
1098 keyrepeat_status = FALSE;
1101 boolean SetVideoMode(boolean fullscreen)
1103 return SDLSetVideoMode(fullscreen);
1106 void SetVideoFrameDelay(unsigned int frame_delay_value)
1108 video.frame_delay.value = frame_delay_value;
1111 unsigned int GetVideoFrameDelay(void)
1113 return video.frame_delay.value;
1116 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1118 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1119 (!fullscreen && video.fullscreen_enabled))
1120 fullscreen = SetVideoMode(fullscreen);
1125 Bitmap *LoadImage(char *filename)
1129 new_bitmap = SDLLoadImage(filename);
1132 new_bitmap->source_filename = getStringCopy(filename);
1137 Bitmap *LoadCustomImage(char *basename)
1139 char *filename = getCustomImageFilename(basename);
1142 if (filename == NULL)
1143 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1145 if ((new_bitmap = LoadImage(filename)) == NULL)
1146 Fail("LoadImage('%s') failed", basename);
1151 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1153 char *filename = getCustomImageFilename(basename);
1156 if (filename == NULL) // (should never happen)
1158 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1163 if (strEqual(filename, bitmap->source_filename))
1165 // The old and new image are the same (have the same filename and path).
1166 // This usually means that this image does not exist in this graphic set
1167 // and a fallback to the existing image is done.
1172 if ((new_bitmap = LoadImage(filename)) == NULL)
1174 Warn("LoadImage('%s') failed", basename);
1179 if (bitmap->width != new_bitmap->width ||
1180 bitmap->height != new_bitmap->height)
1182 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1185 FreeBitmap(new_bitmap);
1190 TransferBitmapPointers(new_bitmap, bitmap);
1194 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1196 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1199 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1201 if (bitmaps[IMG_BITMAP_CUSTOM])
1203 // check if original sized bitmap points to custom sized bitmap
1204 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1206 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1208 // keep pointer of previous custom size bitmap
1209 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1211 // set original bitmap pointer to scaled original bitmap of other size
1212 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1214 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1218 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1221 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1224 if (gfx.game_tile_size == gfx.standard_tile_size)
1226 // set game bitmap pointer to standard sized bitmap (already existing)
1227 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1232 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1233 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1234 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1236 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1238 // set game bitmap pointer to custom sized bitmap (newly created)
1239 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1242 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1243 int tile_size, boolean create_small_bitmaps)
1245 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1246 Bitmap *tmp_bitmap_final = NULL;
1247 Bitmap *tmp_bitmap_0 = NULL;
1248 Bitmap *tmp_bitmap_1 = NULL;
1249 Bitmap *tmp_bitmap_2 = NULL;
1250 Bitmap *tmp_bitmap_4 = NULL;
1251 Bitmap *tmp_bitmap_8 = NULL;
1252 Bitmap *tmp_bitmap_16 = NULL;
1253 Bitmap *tmp_bitmap_32 = NULL;
1254 int width_final, height_final;
1255 int width_0, height_0;
1256 int width_1, height_1;
1257 int width_2, height_2;
1258 int width_4, height_4;
1259 int width_8, height_8;
1260 int width_16, height_16;
1261 int width_32, height_32;
1262 int old_width, old_height;
1265 print_timestamp_init("CreateScaledBitmaps");
1267 old_width = old_bitmap->width;
1268 old_height = old_bitmap->height;
1270 // calculate new image dimensions for final image size
1271 width_final = old_width * zoom_factor;
1272 height_final = old_height * zoom_factor;
1274 // get image with final size (this might require scaling up)
1275 // ("final" size may result in non-standard tile size image)
1276 if (zoom_factor != 1)
1277 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1279 tmp_bitmap_final = old_bitmap;
1281 UPDATE_BUSY_STATE();
1283 width_0 = width_1 = width_final;
1284 height_0 = height_1 = height_final;
1286 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1288 if (create_small_bitmaps)
1290 // check if we have a non-gameplay tile size image
1291 if (tile_size != gfx.game_tile_size)
1293 // get image with gameplay tile size
1294 width_0 = width_final * gfx.game_tile_size / tile_size;
1295 height_0 = height_final * gfx.game_tile_size / tile_size;
1297 if (width_0 == old_width)
1298 tmp_bitmap_0 = old_bitmap;
1299 else if (width_0 == width_final)
1300 tmp_bitmap_0 = tmp_bitmap_final;
1302 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1304 UPDATE_BUSY_STATE();
1307 // check if we have a non-standard tile size image
1308 if (tile_size != gfx.standard_tile_size)
1310 // get image with standard tile size
1311 width_1 = width_final * gfx.standard_tile_size / tile_size;
1312 height_1 = height_final * gfx.standard_tile_size / tile_size;
1314 if (width_1 == old_width)
1315 tmp_bitmap_1 = old_bitmap;
1316 else if (width_1 == width_final)
1317 tmp_bitmap_1 = tmp_bitmap_final;
1318 else if (width_1 == width_0)
1319 tmp_bitmap_1 = tmp_bitmap_0;
1321 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1323 UPDATE_BUSY_STATE();
1326 // calculate new image dimensions for small images
1327 width_2 = width_1 / 2;
1328 height_2 = height_1 / 2;
1329 width_4 = width_1 / 4;
1330 height_4 = height_1 / 4;
1331 width_8 = width_1 / 8;
1332 height_8 = height_1 / 8;
1333 width_16 = width_1 / 16;
1334 height_16 = height_1 / 16;
1335 width_32 = width_1 / 32;
1336 height_32 = height_1 / 32;
1338 // get image with 1/2 of normal size (for use in the level editor)
1339 if (width_2 == old_width)
1340 tmp_bitmap_2 = old_bitmap;
1342 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1344 UPDATE_BUSY_STATE();
1346 // get image with 1/4 of normal size (for use in the level editor)
1347 if (width_4 == old_width)
1348 tmp_bitmap_4 = old_bitmap;
1350 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1352 UPDATE_BUSY_STATE();
1354 // get image with 1/8 of normal size (for use on the preview screen)
1355 if (width_8 == old_width)
1356 tmp_bitmap_8 = old_bitmap;
1358 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1360 UPDATE_BUSY_STATE();
1362 // get image with 1/16 of normal size (for use on the preview screen)
1363 if (width_16 == old_width)
1364 tmp_bitmap_16 = old_bitmap;
1366 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1368 UPDATE_BUSY_STATE();
1370 // get image with 1/32 of normal size (for use on the preview screen)
1371 if (width_32 == old_width)
1372 tmp_bitmap_32 = old_bitmap;
1374 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1376 UPDATE_BUSY_STATE();
1378 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1379 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1380 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1381 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1382 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1383 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1385 if (width_0 != width_1)
1386 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1388 if (bitmaps[IMG_BITMAP_CUSTOM])
1389 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1391 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1393 // store the "final" (up-scaled) original bitmap, if not already stored
1395 int tmp_bitmap_final_nr = -1;
1397 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1398 if (bitmaps[i] == tmp_bitmap_final)
1399 tmp_bitmap_final_nr = i;
1401 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1403 // store pointer of scaled original bitmap (not used for any other size)
1404 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1406 // set original bitmap pointer to scaled original bitmap of other size
1407 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1411 // set original bitmap pointer to corresponding sized bitmap
1412 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1415 // free the "old" (unscaled) original bitmap, if not already stored
1417 boolean free_old_bitmap = TRUE;
1419 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1420 if (bitmaps[i] == old_bitmap)
1421 free_old_bitmap = FALSE;
1423 if (free_old_bitmap)
1425 // copy image filename from old to new standard sized bitmap
1426 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1427 getStringCopy(old_bitmap->source_filename);
1429 FreeBitmap(old_bitmap);
1434 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1436 // set original bitmap pointer to corresponding sized bitmap
1437 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1439 if (old_bitmap != tmp_bitmap_1)
1440 FreeBitmap(old_bitmap);
1443 UPDATE_BUSY_STATE();
1445 print_timestamp_done("CreateScaledBitmaps");
1448 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1451 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1454 void CreateBitmapTextures(Bitmap **bitmaps)
1456 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1457 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1459 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1462 void FreeBitmapTextures(Bitmap **bitmaps)
1464 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1465 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1467 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1470 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1472 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1476 // ----------------------------------------------------------------------------
1477 // mouse pointer functions
1478 // ----------------------------------------------------------------------------
1480 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1482 // XPM image definitions
1483 static const char *cursor_image_none[] =
1485 // width height num_colors chars_per_pixel
1515 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1516 static const char *cursor_image_dot[] =
1518 // width height num_colors chars_per_pixel
1547 static const char **cursor_image_playfield = cursor_image_dot;
1549 // some people complained about a "white dot" on the screen and thought it
1550 // was a graphical error... OK, let's just remove the whole pointer :-)
1551 static const char **cursor_image_playfield = cursor_image_none;
1554 static const int cursor_bit_order = BIT_ORDER_MSB;
1556 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1558 struct MouseCursorInfo *cursor;
1559 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1560 int header_lines = 4;
1563 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1565 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1568 for (y = 0; y < cursor->width; y++)
1570 for (x = 0; x < cursor->height; x++)
1573 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1578 cursor->data[i] = cursor->mask[i] = 0;
1581 switch (image[header_lines + y][x])
1584 cursor->data[i] |= bit_mask;
1585 cursor->mask[i] |= bit_mask;
1589 cursor->mask[i] |= bit_mask;
1598 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1603 void SetMouseCursor(int mode)
1605 static struct MouseCursorInfo *cursor_none = NULL;
1606 static struct MouseCursorInfo *cursor_playfield = NULL;
1607 struct MouseCursorInfo *cursor_new;
1608 int mode_final = mode;
1610 if (cursor_none == NULL)
1611 cursor_none = get_cursor_from_image(cursor_image_none);
1613 if (cursor_playfield == NULL)
1614 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1616 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1617 mode_final = gfx.cursor_mode_override;
1619 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1620 mode_final == CURSOR_NONE ? cursor_none :
1621 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1623 SDLSetMouseCursor(cursor_new);
1625 gfx.cursor_mode = mode;
1626 gfx.cursor_mode_final = mode_final;
1629 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1631 // mouse events do not contain logical screen size corrections yet
1632 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1634 mouse_x -= video.screen_xoffset;
1635 mouse_y -= video.screen_yoffset;
1637 gfx.mouse_x = mouse_x;
1638 gfx.mouse_y = mouse_y;
1641 void UpdateMousePosition(void)
1643 int mouse_x, mouse_y;
1646 SDL_GetMouseState(&mouse_x, &mouse_y);
1648 UpdateRawMousePosition(mouse_x, mouse_y);
1652 // ============================================================================
1654 // ============================================================================
1656 void OpenAudio(void)
1658 // always start with reliable default values
1659 audio.sound_available = FALSE;
1660 audio.music_available = FALSE;
1661 audio.loops_available = FALSE;
1663 audio.sound_enabled = FALSE;
1664 audio.sound_deactivated = FALSE;
1666 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1667 audio.mixer_pid = 0;
1668 audio.device_name = NULL;
1669 audio.device_fd = -1;
1671 audio.num_channels = 0;
1672 audio.music_channel = 0;
1673 audio.first_sound_channel = 0;
1678 void CloseAudio(void)
1682 audio.sound_enabled = FALSE;
1685 void SetAudioMode(boolean enabled)
1687 if (!audio.sound_available)
1690 audio.sound_enabled = enabled;
1694 // ============================================================================
1696 // ============================================================================
1698 void InitEventFilter(EventFilter filter_function)
1700 SDL_SetEventFilter(filter_function, NULL);
1703 boolean PendingEvent(void)
1705 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1708 void WaitEvent(Event *event)
1710 SDLWaitEvent(event);
1713 void PeekEvent(Event *event)
1715 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1718 void PumpEvents(void)
1723 void CheckQuitEvent(void)
1725 if (SDL_QuitRequested())
1726 program.exit_function(0);
1729 Key GetEventKey(KeyEvent *event)
1731 // key up/down events in SDL2 do not return text characters anymore
1732 return event->keysym.sym;
1735 KeyMod HandleKeyModState(Key key, int key_status)
1737 static KeyMod current_modifiers = KMOD_None;
1739 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1741 KeyMod new_modifier = KMOD_None;
1746 new_modifier = KMOD_Shift_L;
1749 new_modifier = KMOD_Shift_R;
1751 case KSYM_Control_L:
1752 new_modifier = KMOD_Control_L;
1754 case KSYM_Control_R:
1755 new_modifier = KMOD_Control_R;
1758 new_modifier = KMOD_Meta_L;
1761 new_modifier = KMOD_Meta_R;
1764 new_modifier = KMOD_Alt_L;
1767 new_modifier = KMOD_Alt_R;
1773 if (key_status == KEY_PRESSED)
1774 current_modifiers |= new_modifier;
1776 current_modifiers &= ~new_modifier;
1779 return current_modifiers;
1782 KeyMod GetKeyModState(void)
1784 return (KeyMod)SDL_GetModState();
1787 KeyMod GetKeyModStateFromEvents(void)
1789 /* always use key modifier state as tracked from key events (this is needed
1790 if the modifier key event was injected into the event queue, but the key
1791 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1792 query the keys as held pressed on the keyboard) -- this case is currently
1793 only used to filter out clipboard insert events from "True X-Mouse" tool */
1795 return HandleKeyModState(KSYM_UNDEFINED, 0);
1798 void StartTextInput(int x, int y, int width, int height)
1800 textinput_status = TRUE;
1802 #if defined(HAS_SCREEN_KEYBOARD)
1803 SDL_StartTextInput();
1805 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1807 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1808 video.shifted_up_delay.count = SDL_GetTicks();
1809 video.shifted_up = TRUE;
1814 void StopTextInput(void)
1816 textinput_status = FALSE;
1818 #if defined(HAS_SCREEN_KEYBOARD)
1819 SDL_StopTextInput();
1821 if (video.shifted_up)
1823 video.shifted_up_pos = 0;
1824 video.shifted_up_delay.count = SDL_GetTicks();
1825 video.shifted_up = FALSE;
1830 void PushUserEvent(int code, int value1, int value2)
1834 SDL_memset(&event, 0, sizeof(event));
1836 event.type = EVENT_USER;
1838 event.value1 = value1;
1839 event.value2 = value2;
1841 SDL_PushEvent((SDL_Event *)&event);
1844 boolean PendingEscapeKeyEvent(void)
1850 // check if any key press event is pending
1851 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1854 // check if pressed key is "Escape" key
1855 if (event.key.keysym.sym == KSYM_Escape)
1863 // ============================================================================
1864 // joystick functions
1865 // ============================================================================
1867 void InitJoysticks(void)
1871 #if defined(NO_JOYSTICK)
1872 return; // joysticks generally deactivated by compile-time directive
1875 // always start with reliable default values
1876 joystick.status = JOYSTICK_NOT_AVAILABLE;
1877 for (i = 0; i < MAX_PLAYERS; i++)
1878 joystick.nr[i] = -1; // no joystick configured
1883 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1885 return SDLReadJoystick(nr, x, y, b1, b2);
1888 boolean CheckJoystickOpened(int nr)
1890 return SDLCheckJoystickOpened(nr);
1893 void ClearJoystickState(void)
1895 SDLClearJoystickState();
1899 // ============================================================================
1900 // Emscripten functions
1901 // ============================================================================
1903 void InitEmscriptenFilesystem(void)
1905 #if defined(PLATFORM_EMSCRIPTEN)
1908 dir = UTF8ToString($0);
1910 Module.sync_done = 0;
1912 FS.mkdir(dir); // create persistent data directory
1913 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1914 FS.syncfs(true, function(err) // sync persistent data into memory
1917 Module.sync_done = 1;
1919 }, PERSISTENT_DIRECTORY);
1921 // wait for persistent data to be synchronized to memory
1922 while (emscripten_run_script_int("Module.sync_done") == 0)
1927 void SyncEmscriptenFilesystem(void)
1929 #if defined(PLATFORM_EMSCRIPTEN)
1932 FS.syncfs(function(err)