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, 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 SDLCreateBitmapContent(new_bitmap, 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 (DrawingDeactivated(dst_x, dst_y))
944 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
945 dst_x, dst_y, BLIT_MASKED);
948 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
949 int src_x, int src_y, int width, int height,
950 int dst_x, int dst_y)
952 if (DrawingOnBackground(dst_x, dst_y))
955 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
959 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
963 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
967 void BlitTexture(Bitmap *bitmap,
968 int src_x, int src_y, int width, int height,
969 int dst_x, int dst_y)
974 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
978 void BlitTextureMasked(Bitmap *bitmap,
979 int src_x, int src_y, int width, int height,
980 int dst_x, int dst_y)
985 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
989 void BlitToScreen(Bitmap *bitmap,
990 int src_x, int src_y, int width, int height,
991 int dst_x, int dst_y)
996 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
997 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
998 width, height, dst_x, dst_y);
1000 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1003 void BlitToScreenMasked(Bitmap *bitmap,
1004 int src_x, int src_y, int width, int height,
1005 int dst_x, int dst_y)
1010 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1011 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1012 width, height, dst_x, dst_y);
1014 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1017 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1020 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1023 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1024 int to_x, int to_y, Pixel pixel, int line_width)
1028 if (program.headless)
1031 for (x = 0; x < line_width; x++)
1033 for (y = 0; y < line_width; y++)
1035 int dx = x - line_width / 2;
1036 int dy = y - line_width / 2;
1038 if ((x == 0 && y == 0) ||
1039 (x == 0 && y == line_width - 1) ||
1040 (x == line_width - 1 && y == 0) ||
1041 (x == line_width - 1 && y == line_width - 1))
1045 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1050 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1055 for (i = 0; i < num_points - 1; i++)
1056 DrawLine(bitmap, points[i].x, points[i].y,
1057 points[i + 1].x, points[i + 1].y, pixel, line_width);
1060 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1064 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1066 if (program.headless)
1069 if (x < 0 || x >= bitmap->width ||
1070 y < 0 || y >= bitmap->height)
1073 return SDLGetPixel(bitmap, x, y);
1076 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1077 unsigned int color_g, unsigned int color_b)
1079 if (program.headless)
1082 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1085 void KeyboardAutoRepeatOn(void)
1087 keyrepeat_status = TRUE;
1090 void KeyboardAutoRepeatOff(void)
1092 keyrepeat_status = FALSE;
1095 boolean SetVideoMode(boolean fullscreen)
1097 return SDLSetVideoMode(fullscreen);
1100 void SetVideoFrameDelay(unsigned int frame_delay_value)
1102 video.frame_delay.value = frame_delay_value;
1105 unsigned int GetVideoFrameDelay(void)
1107 return video.frame_delay.value;
1110 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1112 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1113 (!fullscreen && video.fullscreen_enabled))
1114 fullscreen = SetVideoMode(fullscreen);
1119 Bitmap *LoadImage(char *filename)
1123 new_bitmap = SDLLoadImage(filename);
1126 new_bitmap->source_filename = getStringCopy(filename);
1131 Bitmap *LoadCustomImage(char *basename)
1133 char *filename = getCustomImageFilename(basename);
1136 if (filename == NULL)
1137 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1139 if ((new_bitmap = LoadImage(filename)) == NULL)
1140 Fail("LoadImage('%s') failed", basename);
1145 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1147 char *filename = getCustomImageFilename(basename);
1150 if (filename == NULL) // (should never happen)
1152 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1157 if (strEqual(filename, bitmap->source_filename))
1159 // The old and new image are the same (have the same filename and path).
1160 // This usually means that this image does not exist in this graphic set
1161 // and a fallback to the existing image is done.
1166 if ((new_bitmap = LoadImage(filename)) == NULL)
1168 Warn("LoadImage('%s') failed", basename);
1173 if (bitmap->width != new_bitmap->width ||
1174 bitmap->height != new_bitmap->height)
1176 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1179 FreeBitmap(new_bitmap);
1184 TransferBitmapPointers(new_bitmap, bitmap);
1188 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1190 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1193 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1195 if (bitmaps[IMG_BITMAP_CUSTOM])
1197 // check if original sized bitmap points to custom sized bitmap
1198 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1200 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1202 // keep pointer of previous custom size bitmap
1203 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1205 // set original bitmap pointer to scaled original bitmap of other size
1206 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1208 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1212 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1215 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1218 if (gfx.game_tile_size == gfx.standard_tile_size)
1220 // set game bitmap pointer to standard sized bitmap (already existing)
1221 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1226 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1227 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1228 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1230 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1232 // set game bitmap pointer to custom sized bitmap (newly created)
1233 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1236 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1237 int tile_size, boolean create_small_bitmaps)
1239 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1240 Bitmap *tmp_bitmap_final = NULL;
1241 Bitmap *tmp_bitmap_0 = NULL;
1242 Bitmap *tmp_bitmap_1 = NULL;
1243 Bitmap *tmp_bitmap_2 = NULL;
1244 Bitmap *tmp_bitmap_4 = NULL;
1245 Bitmap *tmp_bitmap_8 = NULL;
1246 Bitmap *tmp_bitmap_16 = NULL;
1247 Bitmap *tmp_bitmap_32 = NULL;
1248 int width_final, height_final;
1249 int width_0, height_0;
1250 int width_1, height_1;
1251 int width_2, height_2;
1252 int width_4, height_4;
1253 int width_8, height_8;
1254 int width_16, height_16;
1255 int width_32, height_32;
1256 int old_width, old_height;
1259 print_timestamp_init("CreateScaledBitmaps");
1261 old_width = old_bitmap->width;
1262 old_height = old_bitmap->height;
1264 // calculate new image dimensions for final image size
1265 width_final = old_width * zoom_factor;
1266 height_final = old_height * zoom_factor;
1268 // get image with final size (this might require scaling up)
1269 // ("final" size may result in non-standard tile size image)
1270 if (zoom_factor != 1)
1271 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1273 tmp_bitmap_final = old_bitmap;
1275 UPDATE_BUSY_STATE();
1277 width_0 = width_1 = width_final;
1278 height_0 = height_1 = height_final;
1280 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1282 if (create_small_bitmaps)
1284 // check if we have a non-gameplay tile size image
1285 if (tile_size != gfx.game_tile_size)
1287 // get image with gameplay tile size
1288 width_0 = width_final * gfx.game_tile_size / tile_size;
1289 height_0 = height_final * gfx.game_tile_size / tile_size;
1291 if (width_0 == old_width)
1292 tmp_bitmap_0 = old_bitmap;
1293 else if (width_0 == width_final)
1294 tmp_bitmap_0 = tmp_bitmap_final;
1296 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1298 UPDATE_BUSY_STATE();
1301 // check if we have a non-standard tile size image
1302 if (tile_size != gfx.standard_tile_size)
1304 // get image with standard tile size
1305 width_1 = width_final * gfx.standard_tile_size / tile_size;
1306 height_1 = height_final * gfx.standard_tile_size / tile_size;
1308 if (width_1 == old_width)
1309 tmp_bitmap_1 = old_bitmap;
1310 else if (width_1 == width_final)
1311 tmp_bitmap_1 = tmp_bitmap_final;
1312 else if (width_1 == width_0)
1313 tmp_bitmap_1 = tmp_bitmap_0;
1315 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1317 UPDATE_BUSY_STATE();
1320 // calculate new image dimensions for small images
1321 width_2 = width_1 / 2;
1322 height_2 = height_1 / 2;
1323 width_4 = width_1 / 4;
1324 height_4 = height_1 / 4;
1325 width_8 = width_1 / 8;
1326 height_8 = height_1 / 8;
1327 width_16 = width_1 / 16;
1328 height_16 = height_1 / 16;
1329 width_32 = width_1 / 32;
1330 height_32 = height_1 / 32;
1332 // get image with 1/2 of normal size (for use in the level editor)
1333 if (width_2 == old_width)
1334 tmp_bitmap_2 = old_bitmap;
1336 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1338 UPDATE_BUSY_STATE();
1340 // get image with 1/4 of normal size (for use in the level editor)
1341 if (width_4 == old_width)
1342 tmp_bitmap_4 = old_bitmap;
1344 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1346 UPDATE_BUSY_STATE();
1348 // get image with 1/8 of normal size (for use on the preview screen)
1349 if (width_8 == old_width)
1350 tmp_bitmap_8 = old_bitmap;
1352 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1354 UPDATE_BUSY_STATE();
1356 // get image with 1/16 of normal size (for use on the preview screen)
1357 if (width_16 == old_width)
1358 tmp_bitmap_16 = old_bitmap;
1360 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1362 UPDATE_BUSY_STATE();
1364 // get image with 1/32 of normal size (for use on the preview screen)
1365 if (width_32 == old_width)
1366 tmp_bitmap_32 = old_bitmap;
1368 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1370 UPDATE_BUSY_STATE();
1372 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1373 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1374 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1375 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1376 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1377 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1379 if (width_0 != width_1)
1380 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1382 if (bitmaps[IMG_BITMAP_CUSTOM])
1383 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1385 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1387 // store the "final" (up-scaled) original bitmap, if not already stored
1389 int tmp_bitmap_final_nr = -1;
1391 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1392 if (bitmaps[i] == tmp_bitmap_final)
1393 tmp_bitmap_final_nr = i;
1395 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1397 // store pointer of scaled original bitmap (not used for any other size)
1398 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1400 // set original bitmap pointer to scaled original bitmap of other size
1401 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1405 // set original bitmap pointer to corresponding sized bitmap
1406 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1409 // free the "old" (unscaled) original bitmap, if not already stored
1411 boolean free_old_bitmap = TRUE;
1413 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1414 if (bitmaps[i] == old_bitmap)
1415 free_old_bitmap = FALSE;
1417 if (free_old_bitmap)
1419 // copy image filename from old to new standard sized bitmap
1420 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1421 getStringCopy(old_bitmap->source_filename);
1423 FreeBitmap(old_bitmap);
1428 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1430 // set original bitmap pointer to corresponding sized bitmap
1431 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1433 if (old_bitmap != tmp_bitmap_1)
1434 FreeBitmap(old_bitmap);
1437 UPDATE_BUSY_STATE();
1439 print_timestamp_done("CreateScaledBitmaps");
1442 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1445 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1448 void CreateBitmapTextures(Bitmap **bitmaps)
1450 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1451 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1453 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1456 void FreeBitmapTextures(Bitmap **bitmaps)
1458 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1459 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1461 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1464 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1466 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1470 // ----------------------------------------------------------------------------
1471 // mouse pointer functions
1472 // ----------------------------------------------------------------------------
1474 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1476 // XPM image definitions
1477 static const char *cursor_image_none[] =
1479 // width height num_colors chars_per_pixel
1509 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1510 static const char *cursor_image_dot[] =
1512 // width height num_colors chars_per_pixel
1541 static const char **cursor_image_playfield = cursor_image_dot;
1543 // some people complained about a "white dot" on the screen and thought it
1544 // was a graphical error... OK, let's just remove the whole pointer :-)
1545 static const char **cursor_image_playfield = cursor_image_none;
1548 static const int cursor_bit_order = BIT_ORDER_MSB;
1550 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1552 struct MouseCursorInfo *cursor;
1553 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1554 int header_lines = 4;
1557 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1559 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1562 for (y = 0; y < cursor->width; y++)
1564 for (x = 0; x < cursor->height; x++)
1567 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1572 cursor->data[i] = cursor->mask[i] = 0;
1575 switch (image[header_lines + y][x])
1578 cursor->data[i] |= bit_mask;
1579 cursor->mask[i] |= bit_mask;
1583 cursor->mask[i] |= bit_mask;
1592 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1597 void SetMouseCursor(int mode)
1599 static struct MouseCursorInfo *cursor_none = NULL;
1600 static struct MouseCursorInfo *cursor_playfield = NULL;
1601 struct MouseCursorInfo *cursor_new;
1602 int mode_final = mode;
1604 if (cursor_none == NULL)
1605 cursor_none = get_cursor_from_image(cursor_image_none);
1607 if (cursor_playfield == NULL)
1608 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1610 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1611 mode_final = gfx.cursor_mode_override;
1613 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1614 mode_final == CURSOR_NONE ? cursor_none :
1615 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1617 SDLSetMouseCursor(cursor_new);
1619 gfx.cursor_mode = mode;
1620 gfx.cursor_mode_final = mode_final;
1623 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1625 // mouse events do not contain logical screen size corrections yet
1626 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1628 mouse_x -= video.screen_xoffset;
1629 mouse_y -= video.screen_yoffset;
1631 gfx.mouse_x = mouse_x;
1632 gfx.mouse_y = mouse_y;
1635 void UpdateMousePosition(void)
1637 int mouse_x, mouse_y;
1640 SDL_GetMouseState(&mouse_x, &mouse_y);
1642 UpdateRawMousePosition(mouse_x, mouse_y);
1646 // ============================================================================
1648 // ============================================================================
1650 void OpenAudio(void)
1652 // always start with reliable default values
1653 audio.sound_available = FALSE;
1654 audio.music_available = FALSE;
1655 audio.loops_available = FALSE;
1657 audio.sound_enabled = FALSE;
1658 audio.sound_deactivated = FALSE;
1660 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1661 audio.mixer_pid = 0;
1662 audio.device_name = NULL;
1663 audio.device_fd = -1;
1665 audio.num_channels = 0;
1666 audio.music_channel = 0;
1667 audio.first_sound_channel = 0;
1672 void CloseAudio(void)
1676 audio.sound_enabled = FALSE;
1679 void SetAudioMode(boolean enabled)
1681 if (!audio.sound_available)
1684 audio.sound_enabled = enabled;
1688 // ============================================================================
1690 // ============================================================================
1692 void InitEventFilter(EventFilter filter_function)
1694 SDL_SetEventFilter(filter_function, NULL);
1697 boolean PendingEvent(void)
1699 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1702 void WaitEvent(Event *event)
1704 SDLWaitEvent(event);
1707 void PeekEvent(Event *event)
1709 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1712 void PumpEvents(void)
1717 void CheckQuitEvent(void)
1719 if (SDL_QuitRequested())
1720 program.exit_function(0);
1723 Key GetEventKey(KeyEvent *event)
1725 // key up/down events in SDL2 do not return text characters anymore
1726 return event->keysym.sym;
1729 KeyMod HandleKeyModState(Key key, int key_status)
1731 static KeyMod current_modifiers = KMOD_None;
1733 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1735 KeyMod new_modifier = KMOD_None;
1740 new_modifier = KMOD_Shift_L;
1743 new_modifier = KMOD_Shift_R;
1745 case KSYM_Control_L:
1746 new_modifier = KMOD_Control_L;
1748 case KSYM_Control_R:
1749 new_modifier = KMOD_Control_R;
1752 new_modifier = KMOD_Meta_L;
1755 new_modifier = KMOD_Meta_R;
1758 new_modifier = KMOD_Alt_L;
1761 new_modifier = KMOD_Alt_R;
1767 if (key_status == KEY_PRESSED)
1768 current_modifiers |= new_modifier;
1770 current_modifiers &= ~new_modifier;
1773 return current_modifiers;
1776 KeyMod GetKeyModState(void)
1778 return (KeyMod)SDL_GetModState();
1781 KeyMod GetKeyModStateFromEvents(void)
1783 /* always use key modifier state as tracked from key events (this is needed
1784 if the modifier key event was injected into the event queue, but the key
1785 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1786 query the keys as held pressed on the keyboard) -- this case is currently
1787 only used to filter out clipboard insert events from "True X-Mouse" tool */
1789 return HandleKeyModState(KSYM_UNDEFINED, 0);
1792 void StartTextInput(int x, int y, int width, int height)
1794 textinput_status = TRUE;
1796 #if defined(HAS_SCREEN_KEYBOARD)
1797 SDL_StartTextInput();
1799 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1801 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1802 video.shifted_up_delay.count = SDL_GetTicks();
1803 video.shifted_up = TRUE;
1808 void StopTextInput(void)
1810 textinput_status = FALSE;
1812 #if defined(HAS_SCREEN_KEYBOARD)
1813 SDL_StopTextInput();
1815 if (video.shifted_up)
1817 video.shifted_up_pos = 0;
1818 video.shifted_up_delay.count = SDL_GetTicks();
1819 video.shifted_up = FALSE;
1824 void PushUserEvent(int code, int value1, int value2)
1828 SDL_memset(&event, 0, sizeof(event));
1830 event.type = EVENT_USER;
1832 event.value1 = value1;
1833 event.value2 = value2;
1835 SDL_PushEvent((SDL_Event *)&event);
1838 boolean PendingEscapeKeyEvent(void)
1844 // check if any key press event is pending
1845 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1848 // check if pressed key is "Escape" key
1849 if (event.key.keysym.sym == KSYM_Escape)
1857 // ============================================================================
1858 // joystick functions
1859 // ============================================================================
1861 void InitJoysticks(void)
1865 #if defined(NO_JOYSTICK)
1866 return; // joysticks generally deactivated by compile-time directive
1869 // always start with reliable default values
1870 joystick.status = JOYSTICK_NOT_AVAILABLE;
1871 for (i = 0; i < MAX_PLAYERS; i++)
1872 joystick.nr[i] = -1; // no joystick configured
1877 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1879 return SDLReadJoystick(nr, x, y, b1, b2);
1882 boolean CheckJoystickOpened(int nr)
1884 return SDLCheckJoystickOpened(nr);
1887 void ClearJoystickState(void)
1889 SDLClearJoystickState();
1893 // ============================================================================
1894 // Emscripten functions
1895 // ============================================================================
1897 void InitEmscriptenFilesystem(void)
1899 #if defined(PLATFORM_EMSCRIPTEN)
1902 dir = UTF8ToString($0);
1904 Module.sync_done = 0;
1906 FS.mkdir(dir); // create persistent data directory
1907 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1908 FS.syncfs(true, function(err) // sync persistent data into memory
1911 Module.sync_done = 1;
1913 }, PERSISTENT_DIRECTORY);
1915 // wait for persistent data to be synchronized to memory
1916 while (emscripten_run_script_int("Module.sync_done") == 0)
1921 void SyncEmscriptenFilesystem(void)
1923 #if defined(PLATFORM_EMSCRIPTEN)
1926 FS.syncfs(function(err)