1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct RuntimeInfo runtime;
34 struct OptionInfo options;
35 struct VideoSystemInfo video;
36 struct AudioSystemInfo audio;
38 struct TileCursorInfo tile_cursor;
39 struct OverlayInfo overlay;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
45 LevelDirTree *leveldir_first_all = NULL;
46 LevelDirTree *leveldir_first = NULL;
47 LevelDirTree *leveldir_current = NULL;
50 struct LevelSetInfo levelset;
51 struct LevelStats level_stats[MAX_LEVELS];
53 DrawWindow *window = NULL;
54 DrawBuffer *backbuffer = NULL;
55 DrawBuffer *drawto = NULL;
57 int button_status = MB_NOT_PRESSED;
58 boolean motion_status = FALSE;
59 int wheel_steps = DEFAULT_WHEEL_STEPS;
60 boolean keyrepeat_status = TRUE;
61 boolean textinput_status = FALSE;
63 int redraw_mask = REDRAW_NONE;
68 // ============================================================================
69 // init/close functions
70 // ============================================================================
72 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
73 char *program_title, char *icon_title,
74 char *icon_filename, char *cookie_prefix,
75 char *program_version_string, int program_version)
77 program.command_basepath = getBasePath(argv0);
78 program.command_basename = getBaseName(argv0);
80 program.config_filename = config_filename;
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_path = getMainUserGameDataDir();
85 program.program_title = program_title;
86 program.window_title = "(undefined)";
87 program.icon_title = icon_title;
89 program.icon_filename = icon_filename;
91 program.cookie_prefix = cookie_prefix;
93 program.version_super = VERSION_SUPER(program_version);
94 program.version_major = VERSION_MAJOR(program_version);
95 program.version_minor = VERSION_MINOR(program_version);
96 program.version_patch = VERSION_PATCH(program_version);
97 program.version_ident = program_version;
99 program.version_string = program_version_string;
101 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
102 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
103 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
104 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
106 program.api_thread_count = 0;
108 program.headless = FALSE;
111 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
112 char *server_host, int server_port)
114 network.enabled = enabled;
115 network.connected = connected;
116 network.serveronly = serveronly;
118 network.server_host = server_host;
119 network.server_port = server_port;
121 network.server_thread = NULL;
122 network.is_server_thread = FALSE;
125 void InitRuntimeInfo()
127 #if defined(HAS_TOUCH_DEVICE)
128 runtime.uses_touch_device = TRUE;
130 runtime.uses_touch_device = FALSE;
133 runtime.use_api_server = setup.use_api_server;
136 void SetWindowTitle(void)
138 program.window_title = program.window_title_function();
143 void InitWindowTitleFunction(char *(*window_title_function)(void))
145 program.window_title_function = window_title_function;
148 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
150 program.exit_message_function = exit_message_function;
153 void InitExitFunction(void (*exit_function)(int))
155 program.exit_function = exit_function;
157 // set signal handlers to custom exit function
158 // signal(SIGINT, exit_function);
159 signal(SIGTERM, exit_function);
161 // set exit function to automatically cleanup SDL stuff after exit()
165 void InitPlatformDependentStuff(void)
167 InitEmscriptenFilesystem();
169 // this is initialized in GetOptions(), but may already be used before
170 options.verbose = TRUE;
174 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
176 if (SDL_Init(sdl_init_flags) < 0)
177 Fail("SDL_Init() failed: %s", SDL_GetError());
182 void ClosePlatformDependentStuff(void)
187 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
188 int real_sx, int real_sy,
189 int full_sxsize, int full_sysize,
190 Bitmap *field_save_buffer)
196 gfx.real_sx = real_sx;
197 gfx.real_sy = real_sy;
198 gfx.full_sxsize = full_sxsize;
199 gfx.full_sysize = full_sysize;
201 gfx.field_save_buffer = field_save_buffer;
203 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
204 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
207 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
209 gfx.game_tile_size = game_tile_size;
210 gfx.standard_tile_size = standard_tile_size;
213 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
221 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
229 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
237 void InitGfxWindowInfo(int win_xsize, int win_ysize)
239 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
241 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
243 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
248 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
250 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
253 gfx.win_xsize = win_xsize;
254 gfx.win_ysize = win_ysize;
256 gfx.background_bitmap_mask = REDRAW_NONE;
259 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
261 // currently only used by MSDOS code to alloc VRAM buffer, if available
262 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
263 gfx.scrollbuffer_width = scrollbuffer_width;
264 gfx.scrollbuffer_height = scrollbuffer_height;
267 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
269 gfx.clipping_enabled = enabled;
272 gfx.clip_width = width;
273 gfx.clip_height = height;
276 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean))
278 gfx.draw_busy_anim_function = draw_busy_anim_function;
281 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
283 gfx.draw_global_anim_function = draw_global_anim_function;
286 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
288 gfx.draw_global_border_function = draw_global_border_function;
291 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
293 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
296 void InitGfxCustomArtworkInfo(void)
298 gfx.override_level_graphics = FALSE;
299 gfx.override_level_sounds = FALSE;
300 gfx.override_level_music = FALSE;
302 gfx.draw_init_text = TRUE;
305 void InitGfxOtherSettings(void)
307 gfx.cursor_mode = CURSOR_DEFAULT;
308 gfx.cursor_mode_override = CURSOR_UNDEFINED;
309 gfx.cursor_mode_final = gfx.cursor_mode;
311 // prevent initially displaying custom mouse cursor in upper left corner
312 gfx.mouse_x = POS_OFFSCREEN;
313 gfx.mouse_y = POS_OFFSCREEN;
316 void InitTileCursorInfo(void)
318 tile_cursor.enabled = FALSE;
319 tile_cursor.active = FALSE;
320 tile_cursor.moving = FALSE;
322 tile_cursor.xpos = 0;
323 tile_cursor.ypos = 0;
326 tile_cursor.target_x = 0;
327 tile_cursor.target_y = 0;
332 tile_cursor.xsn_debug = FALSE;
335 void InitOverlayInfo(void)
337 overlay.enabled = FALSE;
338 overlay.active = FALSE;
340 overlay.show_grid = FALSE;
342 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
343 overlay.grid_button_action = JOY_NO_ACTION;
345 SetOverlayGridSizeAndButtons();
347 #if defined(USE_TOUCH_INPUT_OVERLAY)
348 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
349 overlay.enabled = TRUE;
353 void SetOverlayGridSizeAndButtons(void)
355 int nr = GRID_ACTIVE_NR();
358 overlay.grid_xsize = setup.touch.grid_xsize[nr];
359 overlay.grid_ysize = setup.touch.grid_ysize[nr];
361 for (x = 0; x < MAX_GRID_XSIZE; x++)
362 for (y = 0; y < MAX_GRID_YSIZE; y++)
363 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
366 void SetTileCursorEnabled(boolean enabled)
368 tile_cursor.enabled = enabled;
371 void SetTileCursorActive(boolean active)
373 tile_cursor.active = active;
376 void SetTileCursorTargetXY(int x, int y)
378 // delayed placement of tile selection cursor at target position
379 // (tile cursor will be moved to target position step by step)
381 tile_cursor.xpos = x;
382 tile_cursor.ypos = y;
383 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
384 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
386 tile_cursor.moving = TRUE;
389 void SetTileCursorXY(int x, int y)
391 // immediate placement of tile selection cursor at target position
393 SetTileCursorTargetXY(x, y);
395 tile_cursor.x = tile_cursor.target_x;
396 tile_cursor.y = tile_cursor.target_y;
398 tile_cursor.moving = FALSE;
401 void SetTileCursorSXSY(int sx, int sy)
407 void SetOverlayEnabled(boolean enabled)
409 overlay.enabled = enabled;
412 void SetOverlayActive(boolean active)
414 overlay.active = active;
417 void SetOverlayShowGrid(boolean show_grid)
419 overlay.show_grid = show_grid;
421 SetOverlayActive(show_grid);
424 SetOverlayEnabled(TRUE);
427 boolean GetOverlayEnabled(void)
429 return overlay.enabled;
432 boolean GetOverlayActive(void)
434 return overlay.active;
437 void SetDrawDeactivationMask(int draw_deactivation_mask)
439 gfx.draw_deactivation_mask = draw_deactivation_mask;
442 int GetDrawDeactivationMask(void)
444 return gfx.draw_deactivation_mask;
447 void SetDrawBackgroundMask(int draw_background_mask)
449 gfx.draw_background_mask = draw_background_mask;
452 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
454 if (background_bitmap_tile != NULL)
455 gfx.background_bitmap_mask |= mask;
457 gfx.background_bitmap_mask &= ~mask;
459 if (background_bitmap_tile == NULL) // empty background requested
462 if (mask == REDRAW_ALL)
463 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
464 0, 0, video.width, video.height);
465 else if (mask == REDRAW_FIELD)
466 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
467 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
468 else if (mask == REDRAW_DOOR_1)
469 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
470 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
473 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
475 // remove every mask before setting mask for window
476 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
477 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
478 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
481 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
483 // remove window area mask before setting mask for main area
484 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
485 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
486 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
489 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
491 // remove window area mask before setting mask for door area
492 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
493 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
494 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
498 // ============================================================================
500 // ============================================================================
502 static int GetRealDepth(int depth)
504 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
507 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
508 int width, int height, Pixel color)
510 SDLFillRectangle(bitmap, x, y, width, height, color);
512 if (bitmap == backbuffer)
513 SetRedrawMaskFromArea(x, y, width, height);
516 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
517 int src_x, int src_y, int width, int height,
518 int dst_x, int dst_y, int mask_mode)
520 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
521 dst_x, dst_y, mask_mode);
523 if (dst_bitmap == backbuffer)
524 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
527 void LimitScreenUpdates(boolean enable)
529 SDLLimitScreenUpdates(enable);
532 void InitVideoDefaults(void)
534 video.default_depth = 32;
537 void InitVideoDisplay(void)
539 if (program.headless)
542 SDLInitVideoDisplay();
546 void CloseVideoDisplay(void)
548 KeyboardAutoRepeatOn();
550 SDL_QuitSubSystem(SDL_INIT_VIDEO);
553 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
556 video.height = height;
557 video.depth = GetRealDepth(depth);
559 video.screen_width = width;
560 video.screen_height = height;
561 video.screen_xoffset = 0;
562 video.screen_yoffset = 0;
564 video.fullscreen_available = FULLSCREEN_STATUS;
565 video.fullscreen_enabled = FALSE;
567 video.window_scaling_available = WINDOW_SCALING_STATUS;
569 video.frame_counter = 0;
570 video.frame_delay.count = 0;
571 video.frame_delay.value = GAME_FRAME_DELAY;
573 video.shifted_up = FALSE;
574 video.shifted_up_pos = 0;
575 video.shifted_up_pos_last = 0;
576 video.shifted_up_delay.count = 0;
577 video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
579 SDLInitVideoBuffer(fullscreen);
581 video.initialized = !program.headless;
586 static void FreeBitmapPointers(Bitmap *bitmap)
591 SDLFreeBitmapPointers(bitmap);
593 checked_free(bitmap->source_filename);
594 bitmap->source_filename = NULL;
597 static void TransferBitmapPointers(Bitmap *src_bitmap,
600 if (src_bitmap == NULL || dst_bitmap == NULL)
603 FreeBitmapPointers(dst_bitmap);
605 *dst_bitmap = *src_bitmap;
608 void FreeBitmap(Bitmap *bitmap)
613 FreeBitmapPointers(bitmap);
618 Bitmap *CreateBitmapStruct(void)
620 return checked_calloc(sizeof(Bitmap));
623 Bitmap *CreateBitmap(int width, int height, int depth)
625 Bitmap *new_bitmap = CreateBitmapStruct();
626 int real_width = MAX(1, width); // prevent zero bitmap width
627 int real_height = MAX(1, height); // prevent zero bitmap height
628 int real_depth = GetRealDepth(depth);
630 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
632 new_bitmap->width = real_width;
633 new_bitmap->height = real_height;
638 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
642 // if new bitmap size fits into old one, no need to re-create it
643 if (width <= (*bitmap)->width &&
644 height <= (*bitmap)->height)
647 // else adjust size so that old and new bitmap size fit into it
648 width = MAX(width, (*bitmap)->width);
649 height = MAX(height, (*bitmap)->height);
652 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
656 *bitmap = new_bitmap;
660 TransferBitmapPointers(new_bitmap, *bitmap);
666 static void CloseWindow(DrawWindow *window)
671 void SetRedrawMaskFromArea(int x, int y, int width, int height)
675 int x2 = x + width - 1;
676 int y2 = y + height - 1;
678 if (width == 0 || height == 0)
681 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
682 redraw_mask |= REDRAW_FIELD;
683 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
684 redraw_mask |= REDRAW_DOOR_1;
685 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
686 redraw_mask |= REDRAW_DOOR_2;
687 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
688 redraw_mask |= REDRAW_DOOR_3;
690 redraw_mask = REDRAW_ALL;
693 static boolean CheckDrawingArea(int x, int y, int draw_mask)
695 if (draw_mask == REDRAW_NONE)
698 if (draw_mask & REDRAW_ALL)
701 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
704 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
707 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
710 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
716 boolean DrawingDeactivatedField(void)
718 if (program.headless)
721 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
727 boolean DrawingDeactivated(int x, int y)
729 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
732 boolean DrawingOnBackground(int x, int y)
734 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
735 CheckDrawingArea(x, y, gfx.draw_background_mask));
738 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
739 int *width, int *height, boolean is_dest)
741 int clip_x, clip_y, clip_width, clip_height;
743 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
745 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
746 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
747 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
748 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
754 clip_width = bitmap->width;
755 clip_height = bitmap->height;
758 // skip if rectangle completely outside bitmap
760 if (*x + *width <= clip_x ||
761 *y + *height <= clip_y ||
762 *x >= clip_x + clip_width ||
763 *y >= clip_y + clip_height)
766 // clip if rectangle overlaps bitmap
770 *width -= clip_x - *x;
773 else if (*x + *width > clip_x + clip_width)
775 *width = clip_x + clip_width - *x;
780 *height -= clip_y - *y;
783 else if (*y + *height > clip_y + clip_height)
785 *height = clip_y + clip_height - *y;
791 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
792 int src_x, int src_y, int width, int height,
793 int dst_x, int dst_y)
795 int dst_x_unclipped = dst_x;
796 int dst_y_unclipped = dst_y;
798 if (program.headless)
801 if (src_bitmap == NULL || dst_bitmap == NULL)
804 if (DrawingDeactivated(dst_x, dst_y))
807 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
808 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
811 // source x/y might need adjustment if destination x/y was clipped top/left
812 src_x += dst_x - dst_x_unclipped;
813 src_y += dst_y - dst_y_unclipped;
815 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
816 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
817 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
818 but is already fixed in SVN and should therefore finally be fixed with
819 the next official SDL release, which is probably version 1.2.14.) */
820 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
822 if (src_bitmap == dst_bitmap)
824 // needed when blitting directly to same bitmap -- should not be needed with
825 // recent SDL libraries, but apparently does not work in 1.2.11 directly
827 static Bitmap *tmp_bitmap = NULL;
828 static int tmp_bitmap_xsize = 0;
829 static int tmp_bitmap_ysize = 0;
831 // start with largest static bitmaps for initial bitmap size ...
832 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
834 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
835 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
838 // ... and allow for later re-adjustments due to custom artwork bitmaps
839 if (src_bitmap->width > tmp_bitmap_xsize ||
840 src_bitmap->height > tmp_bitmap_ysize)
842 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
843 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
845 FreeBitmap(tmp_bitmap);
850 if (tmp_bitmap == NULL)
851 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
854 sysCopyArea(src_bitmap, tmp_bitmap,
855 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
856 sysCopyArea(tmp_bitmap, dst_bitmap,
857 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
862 sysCopyArea(src_bitmap, dst_bitmap,
863 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
866 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
867 int src_x, int src_y, int src_width, int src_height,
868 int dst_x, int dst_y, int dst_width, int dst_height)
870 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
871 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
872 int dst_xsize = dst_width;
873 int dst_ysize = dst_height;
874 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
875 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
878 for (y = 0; y < src_ysteps; y++)
880 for (x = 0; x < src_xsteps; x++)
882 int draw_x = dst_x + x * src_xsize;
883 int draw_y = dst_y + y * src_ysize;
884 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
885 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
887 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
893 void FadeRectangle(int x, int y, int width, int height,
894 int fade_mode, int fade_delay, int post_delay,
895 void (*draw_border_function)(void))
897 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
898 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
901 SDLFadeRectangle(x, y, width, height,
902 fade_mode, fade_delay, post_delay, draw_border_function);
905 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
908 if (program.headless)
911 if (DrawingDeactivated(x, y))
914 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
917 sysFillRectangle(bitmap, x, y, width, height, color);
920 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
922 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
925 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
926 int width, int height)
928 if (DrawingOnBackground(x, y))
929 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
931 ClearRectangle(bitmap, x, y, width, height);
934 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
935 int src_x, int src_y, int width, int height,
936 int dst_x, int dst_y)
938 if (DrawingDeactivated(dst_x, dst_y))
941 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
942 dst_x, dst_y, BLIT_MASKED);
945 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
946 int src_x, int src_y, int width, int height,
947 int dst_x, int dst_y)
949 if (DrawingOnBackground(dst_x, dst_y))
952 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
956 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
960 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
964 void BlitTexture(Bitmap *bitmap,
965 int src_x, int src_y, int width, int height,
966 int dst_x, int dst_y)
971 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
975 void BlitTextureMasked(Bitmap *bitmap,
976 int src_x, int src_y, int width, int height,
977 int dst_x, int dst_y)
982 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
986 void BlitToScreen(Bitmap *bitmap,
987 int src_x, int src_y, int width, int height,
988 int dst_x, int dst_y)
993 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
994 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
995 width, height, dst_x, dst_y);
997 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1000 void BlitToScreenMasked(Bitmap *bitmap,
1001 int src_x, int src_y, int width, int height,
1002 int dst_x, int dst_y)
1007 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1008 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1009 width, height, dst_x, dst_y);
1011 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1014 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1017 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1020 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1021 int to_x, int to_y, Pixel pixel, int line_width)
1025 if (program.headless)
1028 for (x = 0; x < line_width; x++)
1030 for (y = 0; y < line_width; y++)
1032 int dx = x - line_width / 2;
1033 int dy = y - line_width / 2;
1035 if ((x == 0 && y == 0) ||
1036 (x == 0 && y == line_width - 1) ||
1037 (x == line_width - 1 && y == 0) ||
1038 (x == line_width - 1 && y == line_width - 1))
1042 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1047 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1052 for (i = 0; i < num_points - 1; i++)
1053 DrawLine(bitmap, points[i].x, points[i].y,
1054 points[i + 1].x, points[i + 1].y, pixel, line_width);
1057 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1061 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1063 if (program.headless)
1066 if (x < 0 || x >= bitmap->width ||
1067 y < 0 || y >= bitmap->height)
1070 return SDLGetPixel(bitmap, x, y);
1073 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1074 unsigned int color_g, unsigned int color_b)
1076 if (program.headless)
1079 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1082 void KeyboardAutoRepeatOn(void)
1084 keyrepeat_status = TRUE;
1087 void KeyboardAutoRepeatOff(void)
1089 keyrepeat_status = FALSE;
1092 boolean SetVideoMode(boolean fullscreen)
1094 return SDLSetVideoMode(fullscreen);
1097 void SetVideoFrameDelay(unsigned int frame_delay_value)
1099 video.frame_delay.value = frame_delay_value;
1102 unsigned int GetVideoFrameDelay(void)
1104 return video.frame_delay.value;
1107 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1109 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1110 (!fullscreen && video.fullscreen_enabled))
1111 fullscreen = SetVideoMode(fullscreen);
1116 Bitmap *LoadImage(char *filename)
1120 new_bitmap = SDLLoadImage(filename);
1123 new_bitmap->source_filename = getStringCopy(filename);
1128 Bitmap *LoadCustomImage(char *basename)
1130 char *filename = getCustomImageFilename(basename);
1133 if (filename == NULL)
1134 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1136 if ((new_bitmap = LoadImage(filename)) == NULL)
1137 Fail("LoadImage('%s') failed", basename);
1142 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1144 char *filename = getCustomImageFilename(basename);
1147 if (filename == NULL) // (should never happen)
1149 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1154 if (strEqual(filename, bitmap->source_filename))
1156 // The old and new image are the same (have the same filename and path).
1157 // This usually means that this image does not exist in this graphic set
1158 // and a fallback to the existing image is done.
1163 if ((new_bitmap = LoadImage(filename)) == NULL)
1165 Warn("LoadImage('%s') failed", basename);
1170 if (bitmap->width != new_bitmap->width ||
1171 bitmap->height != new_bitmap->height)
1173 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1176 FreeBitmap(new_bitmap);
1181 TransferBitmapPointers(new_bitmap, bitmap);
1185 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1187 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1190 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1192 if (bitmaps[IMG_BITMAP_CUSTOM])
1194 // check if original sized bitmap points to custom sized bitmap
1195 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1197 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1199 // keep pointer of previous custom size bitmap
1200 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1202 // set original bitmap pointer to scaled original bitmap of other size
1203 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1205 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1209 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1212 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1215 if (gfx.game_tile_size == gfx.standard_tile_size)
1217 // set game bitmap pointer to standard sized bitmap (already existing)
1218 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1223 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1224 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1225 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1227 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1229 // set game bitmap pointer to custom sized bitmap (newly created)
1230 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1233 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1234 int tile_size, boolean create_small_bitmaps)
1236 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1237 Bitmap *tmp_bitmap_final = NULL;
1238 Bitmap *tmp_bitmap_0 = NULL;
1239 Bitmap *tmp_bitmap_1 = NULL;
1240 Bitmap *tmp_bitmap_2 = NULL;
1241 Bitmap *tmp_bitmap_4 = NULL;
1242 Bitmap *tmp_bitmap_8 = NULL;
1243 Bitmap *tmp_bitmap_16 = NULL;
1244 Bitmap *tmp_bitmap_32 = NULL;
1245 int width_final, height_final;
1246 int width_0, height_0;
1247 int width_1, height_1;
1248 int width_2, height_2;
1249 int width_4, height_4;
1250 int width_8, height_8;
1251 int width_16, height_16;
1252 int width_32, height_32;
1253 int old_width, old_height;
1256 print_timestamp_init("CreateScaledBitmaps");
1258 old_width = old_bitmap->width;
1259 old_height = old_bitmap->height;
1261 // calculate new image dimensions for final image size
1262 width_final = old_width * zoom_factor;
1263 height_final = old_height * zoom_factor;
1265 // get image with final size (this might require scaling up)
1266 // ("final" size may result in non-standard tile size image)
1267 if (zoom_factor != 1)
1268 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1270 tmp_bitmap_final = old_bitmap;
1272 UPDATE_BUSY_STATE();
1274 width_0 = width_1 = width_final;
1275 height_0 = height_1 = height_final;
1277 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1279 if (create_small_bitmaps)
1281 // check if we have a non-gameplay tile size image
1282 if (tile_size != gfx.game_tile_size)
1284 // get image with gameplay tile size
1285 width_0 = width_final * gfx.game_tile_size / tile_size;
1286 height_0 = height_final * gfx.game_tile_size / tile_size;
1288 if (width_0 == old_width)
1289 tmp_bitmap_0 = old_bitmap;
1290 else if (width_0 == width_final)
1291 tmp_bitmap_0 = tmp_bitmap_final;
1293 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1295 UPDATE_BUSY_STATE();
1298 // check if we have a non-standard tile size image
1299 if (tile_size != gfx.standard_tile_size)
1301 // get image with standard tile size
1302 width_1 = width_final * gfx.standard_tile_size / tile_size;
1303 height_1 = height_final * gfx.standard_tile_size / tile_size;
1305 if (width_1 == old_width)
1306 tmp_bitmap_1 = old_bitmap;
1307 else if (width_1 == width_final)
1308 tmp_bitmap_1 = tmp_bitmap_final;
1309 else if (width_1 == width_0)
1310 tmp_bitmap_1 = tmp_bitmap_0;
1312 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1314 UPDATE_BUSY_STATE();
1317 // calculate new image dimensions for small images
1318 width_2 = width_1 / 2;
1319 height_2 = height_1 / 2;
1320 width_4 = width_1 / 4;
1321 height_4 = height_1 / 4;
1322 width_8 = width_1 / 8;
1323 height_8 = height_1 / 8;
1324 width_16 = width_1 / 16;
1325 height_16 = height_1 / 16;
1326 width_32 = width_1 / 32;
1327 height_32 = height_1 / 32;
1329 // get image with 1/2 of normal size (for use in the level editor)
1330 if (width_2 == old_width)
1331 tmp_bitmap_2 = old_bitmap;
1333 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1335 UPDATE_BUSY_STATE();
1337 // get image with 1/4 of normal size (for use in the level editor)
1338 if (width_4 == old_width)
1339 tmp_bitmap_4 = old_bitmap;
1341 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1343 UPDATE_BUSY_STATE();
1345 // get image with 1/8 of normal size (for use on the preview screen)
1346 if (width_8 == old_width)
1347 tmp_bitmap_8 = old_bitmap;
1349 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1351 UPDATE_BUSY_STATE();
1353 // get image with 1/16 of normal size (for use on the preview screen)
1354 if (width_16 == old_width)
1355 tmp_bitmap_16 = old_bitmap;
1357 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1359 UPDATE_BUSY_STATE();
1361 // get image with 1/32 of normal size (for use on the preview screen)
1362 if (width_32 == old_width)
1363 tmp_bitmap_32 = old_bitmap;
1365 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1367 UPDATE_BUSY_STATE();
1369 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1370 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1371 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1372 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1373 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1374 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1376 if (width_0 != width_1)
1377 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1379 if (bitmaps[IMG_BITMAP_CUSTOM])
1380 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1382 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1384 // store the "final" (up-scaled) original bitmap, if not already stored
1386 int tmp_bitmap_final_nr = -1;
1388 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1389 if (bitmaps[i] == tmp_bitmap_final)
1390 tmp_bitmap_final_nr = i;
1392 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1394 // store pointer of scaled original bitmap (not used for any other size)
1395 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1397 // set original bitmap pointer to scaled original bitmap of other size
1398 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1402 // set original bitmap pointer to corresponding sized bitmap
1403 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1406 // free the "old" (unscaled) original bitmap, if not already stored
1408 boolean free_old_bitmap = TRUE;
1410 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1411 if (bitmaps[i] == old_bitmap)
1412 free_old_bitmap = FALSE;
1414 if (free_old_bitmap)
1416 // copy image filename from old to new standard sized bitmap
1417 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1418 getStringCopy(old_bitmap->source_filename);
1420 FreeBitmap(old_bitmap);
1425 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1427 // set original bitmap pointer to corresponding sized bitmap
1428 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1430 if (old_bitmap != tmp_bitmap_1)
1431 FreeBitmap(old_bitmap);
1434 UPDATE_BUSY_STATE();
1436 print_timestamp_done("CreateScaledBitmaps");
1439 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1442 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1445 void CreateBitmapTextures(Bitmap **bitmaps)
1447 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1448 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1450 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1453 void FreeBitmapTextures(Bitmap **bitmaps)
1455 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1456 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1458 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1461 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1463 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1467 // ----------------------------------------------------------------------------
1468 // mouse pointer functions
1469 // ----------------------------------------------------------------------------
1471 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1473 // XPM image definitions
1474 static const char *cursor_image_none[] =
1476 // width height num_colors chars_per_pixel
1506 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1507 static const char *cursor_image_dot[] =
1509 // width height num_colors chars_per_pixel
1538 static const char **cursor_image_playfield = cursor_image_dot;
1540 // some people complained about a "white dot" on the screen and thought it
1541 // was a graphical error... OK, let's just remove the whole pointer :-)
1542 static const char **cursor_image_playfield = cursor_image_none;
1545 static const int cursor_bit_order = BIT_ORDER_MSB;
1547 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1549 struct MouseCursorInfo *cursor;
1550 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1551 int header_lines = 4;
1554 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1556 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1559 for (y = 0; y < cursor->width; y++)
1561 for (x = 0; x < cursor->height; x++)
1564 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1569 cursor->data[i] = cursor->mask[i] = 0;
1572 switch (image[header_lines + y][x])
1575 cursor->data[i] |= bit_mask;
1576 cursor->mask[i] |= bit_mask;
1580 cursor->mask[i] |= bit_mask;
1589 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1594 void SetMouseCursor(int mode)
1596 static struct MouseCursorInfo *cursor_none = NULL;
1597 static struct MouseCursorInfo *cursor_playfield = NULL;
1598 struct MouseCursorInfo *cursor_new;
1599 int mode_final = mode;
1601 if (cursor_none == NULL)
1602 cursor_none = get_cursor_from_image(cursor_image_none);
1604 if (cursor_playfield == NULL)
1605 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1607 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1608 mode_final = gfx.cursor_mode_override;
1610 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1611 mode_final == CURSOR_NONE ? cursor_none :
1612 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1614 SDLSetMouseCursor(cursor_new);
1616 gfx.cursor_mode = mode;
1617 gfx.cursor_mode_final = mode_final;
1620 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1622 // mouse events do not contain logical screen size corrections yet
1623 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1625 mouse_x -= video.screen_xoffset;
1626 mouse_y -= video.screen_yoffset;
1628 gfx.mouse_x = mouse_x;
1629 gfx.mouse_y = mouse_y;
1632 void UpdateMousePosition(void)
1634 int mouse_x, mouse_y;
1637 SDL_GetMouseState(&mouse_x, &mouse_y);
1639 UpdateRawMousePosition(mouse_x, mouse_y);
1643 // ============================================================================
1645 // ============================================================================
1647 void OpenAudio(void)
1649 // always start with reliable default values
1650 audio.sound_available = FALSE;
1651 audio.music_available = FALSE;
1652 audio.loops_available = FALSE;
1654 audio.sound_enabled = FALSE;
1655 audio.sound_deactivated = FALSE;
1657 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1658 audio.mixer_pid = 0;
1659 audio.device_name = NULL;
1660 audio.device_fd = -1;
1662 audio.num_channels = 0;
1663 audio.music_channel = 0;
1664 audio.first_sound_channel = 0;
1669 void CloseAudio(void)
1673 audio.sound_enabled = FALSE;
1676 void SetAudioMode(boolean enabled)
1678 if (!audio.sound_available)
1681 audio.sound_enabled = enabled;
1685 // ============================================================================
1687 // ============================================================================
1689 void InitEventFilter(EventFilter filter_function)
1691 SDL_SetEventFilter(filter_function, NULL);
1694 boolean PendingEvent(void)
1696 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1699 void WaitEvent(Event *event)
1701 SDLWaitEvent(event);
1704 void PeekEvent(Event *event)
1706 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1709 void PumpEvents(void)
1714 void CheckQuitEvent(void)
1716 if (SDL_QuitRequested())
1717 program.exit_function(0);
1720 Key GetEventKey(KeyEvent *event)
1722 // key up/down events in SDL2 do not return text characters anymore
1723 return event->keysym.sym;
1726 KeyMod HandleKeyModState(Key key, int key_status)
1728 static KeyMod current_modifiers = KMOD_None;
1730 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1732 KeyMod new_modifier = KMOD_None;
1737 new_modifier = KMOD_Shift_L;
1740 new_modifier = KMOD_Shift_R;
1742 case KSYM_Control_L:
1743 new_modifier = KMOD_Control_L;
1745 case KSYM_Control_R:
1746 new_modifier = KMOD_Control_R;
1749 new_modifier = KMOD_Meta_L;
1752 new_modifier = KMOD_Meta_R;
1755 new_modifier = KMOD_Alt_L;
1758 new_modifier = KMOD_Alt_R;
1764 if (key_status == KEY_PRESSED)
1765 current_modifiers |= new_modifier;
1767 current_modifiers &= ~new_modifier;
1770 return current_modifiers;
1773 KeyMod GetKeyModState(void)
1775 return (KeyMod)SDL_GetModState();
1778 KeyMod GetKeyModStateFromEvents(void)
1780 /* always use key modifier state as tracked from key events (this is needed
1781 if the modifier key event was injected into the event queue, but the key
1782 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1783 query the keys as held pressed on the keyboard) -- this case is currently
1784 only used to filter out clipboard insert events from "True X-Mouse" tool */
1786 return HandleKeyModState(KSYM_UNDEFINED, 0);
1789 void StartTextInput(int x, int y, int width, int height)
1791 textinput_status = TRUE;
1793 #if defined(HAS_SCREEN_KEYBOARD)
1794 SDL_StartTextInput();
1796 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1798 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1799 video.shifted_up_delay.count = SDL_GetTicks();
1800 video.shifted_up = TRUE;
1805 void StopTextInput(void)
1807 textinput_status = FALSE;
1809 #if defined(HAS_SCREEN_KEYBOARD)
1810 SDL_StopTextInput();
1812 if (video.shifted_up)
1814 video.shifted_up_pos = 0;
1815 video.shifted_up_delay.count = SDL_GetTicks();
1816 video.shifted_up = FALSE;
1821 void PushUserEvent(int code, int value1, int value2)
1825 SDL_memset(&event, 0, sizeof(event));
1827 event.type = EVENT_USER;
1829 event.value1 = value1;
1830 event.value2 = value2;
1832 SDL_PushEvent((SDL_Event *)&event);
1835 boolean PendingEscapeKeyEvent(void)
1841 // check if any key press event is pending
1842 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1845 // check if pressed key is "Escape" key
1846 if (event.key.keysym.sym == KSYM_Escape)
1854 // ============================================================================
1855 // joystick functions
1856 // ============================================================================
1858 void InitJoysticks(void)
1862 #if defined(NO_JOYSTICK)
1863 return; // joysticks generally deactivated by compile-time directive
1866 // always start with reliable default values
1867 joystick.status = JOYSTICK_NOT_AVAILABLE;
1868 for (i = 0; i < MAX_PLAYERS; i++)
1869 joystick.nr[i] = -1; // no joystick configured
1874 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1876 return SDLReadJoystick(nr, x, y, b1, b2);
1879 boolean CheckJoystickOpened(int nr)
1881 return SDLCheckJoystickOpened(nr);
1884 void ClearJoystickState(void)
1886 SDLClearJoystickState();
1890 // ============================================================================
1891 // Emscripten functions
1892 // ============================================================================
1894 void InitEmscriptenFilesystem(void)
1896 #if defined(PLATFORM_EMSCRIPTEN)
1899 dir = UTF8ToString($0);
1901 Module.sync_done = 0;
1903 FS.mkdir(dir); // create persistent data directory
1904 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1905 FS.syncfs(true, function(err) // sync persistent data into memory
1908 Module.sync_done = 1;
1910 }, PERSISTENT_DIRECTORY);
1912 // wait for persistent data to be synchronized to memory
1913 while (emscripten_run_script_int("Module.sync_done") == 0)
1918 void SyncEmscriptenFilesystem(void)
1920 #if defined(PLATFORM_EMSCRIPTEN)
1923 FS.syncfs(function(err)