1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct RuntimeInfo runtime;
34 struct OptionInfo options;
35 struct VideoSystemInfo video;
36 struct AudioSystemInfo audio;
38 struct TileCursorInfo tile_cursor;
39 struct OverlayInfo overlay;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
45 LevelDirTree *leveldir_first_all = NULL;
46 LevelDirTree *leveldir_first = NULL;
47 LevelDirTree *leveldir_current = NULL;
50 struct LevelSetInfo levelset;
51 struct LevelStats level_stats[MAX_LEVELS];
53 DrawWindow *window = NULL;
54 DrawBuffer *backbuffer = NULL;
55 DrawBuffer *drawto = NULL;
57 int button_status = MB_NOT_PRESSED;
58 boolean motion_status = FALSE;
59 int wheel_steps = DEFAULT_WHEEL_STEPS;
60 boolean keyrepeat_status = TRUE;
61 boolean textinput_status = FALSE;
63 int redraw_mask = REDRAW_NONE;
68 // ============================================================================
69 // init/close functions
70 // ============================================================================
72 void InitProgramInfo(char *command_filename,
73 char *config_filename, char *userdata_subdir,
74 char *program_basename, char *program_title,
75 char *icon_filename, char *cookie_prefix,
76 char *program_version_string, int program_version)
78 program.command_basepath = getBasePath(command_filename);
79 program.command_basename = getBaseName(command_filename);
81 program.config_filename = config_filename;
83 program.userdata_subdir = userdata_subdir;
84 program.userdata_path = getMainUserGameDataDir();
86 program.program_basename = program_basename;
87 program.program_title = program_title;
88 program.window_title = "(undefined)";
90 program.icon_filename = icon_filename;
92 program.cookie_prefix = cookie_prefix;
94 program.version_super = VERSION_SUPER(program_version);
95 program.version_major = VERSION_MAJOR(program_version);
96 program.version_minor = VERSION_MINOR(program_version);
97 program.version_patch = VERSION_PATCH(program_version);
98 program.version_ident = program_version;
100 program.version_string = program_version_string;
102 program.log_filename = getLogFilename(getLogBasename(program_basename));
103 program.log_file = program.log_file_default = stdout;
105 program.api_thread_count = 0;
107 program.headless = FALSE;
110 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
111 char *server_host, int server_port)
113 network.enabled = enabled;
114 network.connected = connected;
115 network.serveronly = serveronly;
117 network.server_host = server_host;
118 network.server_port = server_port;
120 network.server_thread = NULL;
121 network.is_server_thread = FALSE;
124 void InitRuntimeInfo()
126 #if defined(HAS_TOUCH_DEVICE)
127 runtime.uses_touch_device = TRUE;
129 runtime.uses_touch_device = FALSE;
132 runtime.use_api_server = setup.use_api_server;
135 void SetWindowTitle(void)
137 program.window_title = program.window_title_function();
142 void InitWindowTitleFunction(char *(*window_title_function)(void))
144 program.window_title_function = window_title_function;
147 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
149 program.exit_message_function = exit_message_function;
152 void InitExitFunction(void (*exit_function)(int))
154 program.exit_function = exit_function;
156 // set signal handlers to custom exit function
157 // signal(SIGINT, exit_function);
158 signal(SIGTERM, exit_function);
160 // set exit function to automatically cleanup SDL stuff after exit()
164 void InitPlatformDependentStuff(void)
166 InitEmscriptenFilesystem();
168 // this is initialized in GetOptions(), but may already be used before
169 options.verbose = TRUE;
173 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
175 if (SDL_Init(sdl_init_flags) < 0)
176 Fail("SDL_Init() failed: %s", SDL_GetError());
181 void ClosePlatformDependentStuff(void)
186 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
187 int real_sx, int real_sy,
188 int full_sxsize, int full_sysize,
189 Bitmap *field_save_buffer)
195 gfx.real_sx = real_sx;
196 gfx.real_sy = real_sy;
197 gfx.full_sxsize = full_sxsize;
198 gfx.full_sysize = full_sysize;
200 gfx.field_save_buffer = field_save_buffer;
202 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
203 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
206 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
208 gfx.game_tile_size = game_tile_size;
209 gfx.standard_tile_size = standard_tile_size;
212 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
220 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
228 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
236 void InitGfxWindowInfo(int win_xsize, int win_ysize)
238 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
240 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
242 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
249 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
252 gfx.win_xsize = win_xsize;
253 gfx.win_ysize = win_ysize;
255 gfx.background_bitmap_mask = REDRAW_NONE;
258 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
260 // currently only used by MSDOS code to alloc VRAM buffer, if available
261 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
262 gfx.scrollbuffer_width = scrollbuffer_width;
263 gfx.scrollbuffer_height = scrollbuffer_height;
266 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
268 gfx.clipping_enabled = enabled;
271 gfx.clip_width = width;
272 gfx.clip_height = height;
275 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean))
277 gfx.draw_busy_anim_function = draw_busy_anim_function;
280 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
282 gfx.draw_global_anim_function = draw_global_anim_function;
285 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
287 gfx.draw_global_border_function = draw_global_border_function;
290 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
292 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
295 void InitGfxCustomArtworkInfo(void)
297 gfx.override_level_graphics = FALSE;
298 gfx.override_level_sounds = FALSE;
299 gfx.override_level_music = FALSE;
301 gfx.draw_init_text = TRUE;
304 void InitGfxOtherSettings(void)
306 gfx.cursor_mode = CURSOR_DEFAULT;
307 gfx.cursor_mode_override = CURSOR_UNDEFINED;
308 gfx.cursor_mode_final = gfx.cursor_mode;
310 // prevent initially displaying custom mouse cursor in upper left corner
311 gfx.mouse_x = POS_OFFSCREEN;
312 gfx.mouse_y = POS_OFFSCREEN;
315 void InitTileCursorInfo(void)
317 tile_cursor.enabled = FALSE;
318 tile_cursor.active = FALSE;
319 tile_cursor.moving = FALSE;
321 tile_cursor.xpos = 0;
322 tile_cursor.ypos = 0;
325 tile_cursor.target_x = 0;
326 tile_cursor.target_y = 0;
331 tile_cursor.xsn_debug = FALSE;
334 void InitOverlayInfo(void)
336 overlay.enabled = FALSE;
337 overlay.active = FALSE;
339 overlay.show_grid = FALSE;
341 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
342 overlay.grid_button_action = JOY_NO_ACTION;
344 SetOverlayGridSizeAndButtons();
346 #if defined(USE_TOUCH_INPUT_OVERLAY)
347 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
348 overlay.enabled = TRUE;
352 void SetOverlayGridSizeAndButtons(void)
354 int nr = GRID_ACTIVE_NR();
357 overlay.grid_xsize = setup.touch.grid_xsize[nr];
358 overlay.grid_ysize = setup.touch.grid_ysize[nr];
360 for (x = 0; x < MAX_GRID_XSIZE; x++)
361 for (y = 0; y < MAX_GRID_YSIZE; y++)
362 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
365 void SetTileCursorEnabled(boolean enabled)
367 tile_cursor.enabled = enabled;
370 void SetTileCursorActive(boolean active)
372 tile_cursor.active = active;
375 void SetTileCursorTargetXY(int x, int y)
377 // delayed placement of tile selection cursor at target position
378 // (tile cursor will be moved to target position step by step)
380 tile_cursor.xpos = x;
381 tile_cursor.ypos = y;
382 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
383 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
385 tile_cursor.moving = TRUE;
388 void SetTileCursorXY(int x, int y)
390 // immediate placement of tile selection cursor at target position
392 SetTileCursorTargetXY(x, y);
394 tile_cursor.x = tile_cursor.target_x;
395 tile_cursor.y = tile_cursor.target_y;
397 tile_cursor.moving = FALSE;
400 void SetTileCursorSXSY(int sx, int sy)
406 void SetOverlayEnabled(boolean enabled)
408 overlay.enabled = enabled;
411 void SetOverlayActive(boolean active)
413 overlay.active = active;
416 void SetOverlayShowGrid(boolean show_grid)
418 overlay.show_grid = show_grid;
420 SetOverlayActive(show_grid);
423 SetOverlayEnabled(TRUE);
426 boolean GetOverlayEnabled(void)
428 return overlay.enabled;
431 boolean GetOverlayActive(void)
433 return overlay.active;
436 void SetDrawDeactivationMask(int draw_deactivation_mask)
438 gfx.draw_deactivation_mask = draw_deactivation_mask;
441 int GetDrawDeactivationMask(void)
443 return gfx.draw_deactivation_mask;
446 void SetDrawBackgroundMask(int draw_background_mask)
448 gfx.draw_background_mask = draw_background_mask;
451 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask,
452 int x, int y, int width, int height)
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,
465 0, 0, video.width, video.height);
466 else if (mask == REDRAW_FIELD)
467 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
469 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
470 else if (mask == REDRAW_DOOR_1)
471 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
473 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
477 // ============================================================================
479 // ============================================================================
481 static int GetRealDepth(int depth)
483 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
486 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
487 int width, int height, Pixel color)
489 SDLFillRectangle(bitmap, x, y, width, height, color);
491 if (bitmap == backbuffer)
492 SetRedrawMaskFromArea(x, y, width, height);
495 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
496 int src_x, int src_y, int width, int height,
497 int dst_x, int dst_y, int mask_mode)
499 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
500 dst_x, dst_y, mask_mode);
502 if (dst_bitmap == backbuffer)
503 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
506 void LimitScreenUpdates(boolean enable)
508 SDLLimitScreenUpdates(enable);
511 void InitVideoDefaults(void)
513 video.default_depth = 32;
516 void InitVideoDisplay(void)
518 if (program.headless)
521 SDLInitVideoDisplay();
525 void CloseVideoDisplay(void)
527 KeyboardAutoRepeatOn();
529 SDL_QuitSubSystem(SDL_INIT_VIDEO);
532 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
535 video.height = height;
536 video.depth = GetRealDepth(depth);
538 video.screen_width = width;
539 video.screen_height = height;
540 video.screen_xoffset = 0;
541 video.screen_yoffset = 0;
543 video.fullscreen_available = FULLSCREEN_STATUS;
544 video.fullscreen_enabled = FALSE;
546 video.window_scaling_available = WINDOW_SCALING_STATUS;
548 video.frame_counter = 0;
549 video.frame_delay.count = 0;
550 video.frame_delay.value = GAME_FRAME_DELAY;
552 video.shifted_up = FALSE;
553 video.shifted_up_pos = 0;
554 video.shifted_up_pos_last = 0;
555 video.shifted_up_delay.count = 0;
556 video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
558 SDLInitVideoBuffer(fullscreen);
560 video.initialized = !program.headless;
565 static void FreeBitmapPointers(Bitmap *bitmap)
570 SDLFreeBitmapPointers(bitmap);
572 checked_free(bitmap->source_filename);
573 bitmap->source_filename = NULL;
576 static void TransferBitmapPointers(Bitmap *src_bitmap,
579 if (src_bitmap == NULL || dst_bitmap == NULL)
582 FreeBitmapPointers(dst_bitmap);
584 *dst_bitmap = *src_bitmap;
587 void FreeBitmap(Bitmap *bitmap)
592 FreeBitmapPointers(bitmap);
597 Bitmap *CreateBitmapStruct(void)
599 return checked_calloc(sizeof(Bitmap));
602 Bitmap *CreateBitmap(int width, int height, int depth)
604 Bitmap *new_bitmap = CreateBitmapStruct();
605 int real_width = MAX(1, width); // prevent zero bitmap width
606 int real_height = MAX(1, height); // prevent zero bitmap height
607 int real_depth = GetRealDepth(depth);
609 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
611 new_bitmap->width = real_width;
612 new_bitmap->height = real_height;
617 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
621 // if new bitmap size fits into old one, no need to re-create it
622 if (width <= (*bitmap)->width &&
623 height <= (*bitmap)->height)
626 // else adjust size so that old and new bitmap size fit into it
627 width = MAX(width, (*bitmap)->width);
628 height = MAX(height, (*bitmap)->height);
631 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
635 *bitmap = new_bitmap;
639 TransferBitmapPointers(new_bitmap, *bitmap);
645 static void CloseWindow(DrawWindow *window)
650 void SetRedrawMaskFromArea(int x, int y, int width, int height)
654 int x2 = x + width - 1;
655 int y2 = y + height - 1;
657 if (width == 0 || height == 0)
660 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
661 redraw_mask |= REDRAW_FIELD;
662 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
663 redraw_mask |= REDRAW_DOOR_1;
664 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
665 redraw_mask |= REDRAW_DOOR_2;
666 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
667 redraw_mask |= REDRAW_DOOR_3;
669 redraw_mask = REDRAW_ALL;
672 static boolean CheckDrawingArea(int x, int y, int draw_mask)
674 if (draw_mask == REDRAW_NONE)
677 if (draw_mask & REDRAW_ALL)
680 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
683 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
686 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
689 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
695 boolean DrawingDeactivatedField(void)
697 if (program.headless)
700 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
706 boolean DrawingDeactivated(int x, int y)
708 return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
711 boolean DrawingOnBackground(int x, int y)
713 return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
714 CheckDrawingArea(x, y, gfx.draw_background_mask));
717 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
718 int *width, int *height, boolean is_dest)
720 int clip_x, clip_y, clip_width, clip_height;
722 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
724 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
725 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
726 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
727 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
733 clip_width = bitmap->width;
734 clip_height = bitmap->height;
737 // skip if rectangle completely outside bitmap
739 if (*x + *width <= clip_x ||
740 *y + *height <= clip_y ||
741 *x >= clip_x + clip_width ||
742 *y >= clip_y + clip_height)
745 // clip if rectangle overlaps bitmap
749 *width -= clip_x - *x;
752 else if (*x + *width > clip_x + clip_width)
754 *width = clip_x + clip_width - *x;
759 *height -= clip_y - *y;
762 else if (*y + *height > clip_y + clip_height)
764 *height = clip_y + clip_height - *y;
770 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
771 int src_x, int src_y, int width, int height,
772 int dst_x, int dst_y)
774 int dst_x_unclipped = dst_x;
775 int dst_y_unclipped = dst_y;
777 if (program.headless)
780 if (src_bitmap == NULL || dst_bitmap == NULL)
783 if (DrawingDeactivated(dst_x, dst_y))
786 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
787 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
790 // source x/y might need adjustment if destination x/y was clipped top/left
791 src_x += dst_x - dst_x_unclipped;
792 src_y += dst_y - dst_y_unclipped;
794 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
795 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
796 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
797 but is already fixed in SVN and should therefore finally be fixed with
798 the next official SDL release, which is probably version 1.2.14.) */
799 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
801 if (src_bitmap == dst_bitmap)
803 // needed when blitting directly to same bitmap -- should not be needed with
804 // recent SDL libraries, but apparently does not work in 1.2.11 directly
806 static Bitmap *tmp_bitmap = NULL;
807 static int tmp_bitmap_xsize = 0;
808 static int tmp_bitmap_ysize = 0;
810 // start with largest static bitmaps for initial bitmap size ...
811 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
813 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
814 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
817 // ... and allow for later re-adjustments due to custom artwork bitmaps
818 if (src_bitmap->width > tmp_bitmap_xsize ||
819 src_bitmap->height > tmp_bitmap_ysize)
821 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
822 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
824 FreeBitmap(tmp_bitmap);
829 if (tmp_bitmap == NULL)
830 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
833 sysCopyArea(src_bitmap, tmp_bitmap,
834 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
835 sysCopyArea(tmp_bitmap, dst_bitmap,
836 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
841 sysCopyArea(src_bitmap, dst_bitmap,
842 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
845 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
846 int src_x, int src_y, int src_width, int src_height,
847 int dst_x, int dst_y, int dst_width, int dst_height)
849 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
850 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
851 int dst_xsize = dst_width;
852 int dst_ysize = dst_height;
853 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
854 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
857 for (y = 0; y < src_ysteps; y++)
859 for (x = 0; x < src_xsteps; x++)
861 int draw_x = dst_x + x * src_xsize;
862 int draw_y = dst_y + y * src_ysize;
863 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
864 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
866 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
872 void FadeRectangle(int x, int y, int width, int height,
873 int fade_mode, int fade_delay, int post_delay,
874 void (*draw_border_function)(void))
876 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
877 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
880 SDLFadeRectangle(x, y, width, height,
881 fade_mode, fade_delay, post_delay, draw_border_function);
884 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
887 if (program.headless)
890 if (DrawingDeactivated(x, y))
893 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
896 sysFillRectangle(bitmap, x, y, width, height, color);
899 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
901 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
904 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
905 int width, int height)
907 if (DrawingOnBackground(x, y))
908 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
910 ClearRectangle(bitmap, x, y, width, height);
913 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
914 int src_x, int src_y, int width, int height,
915 int dst_x, int dst_y)
917 if (DrawingDeactivated(dst_x, dst_y))
920 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
921 dst_x, dst_y, BLIT_MASKED);
924 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
925 int src_x, int src_y, int width, int height,
926 int dst_x, int dst_y)
928 if (DrawingOnBackground(dst_x, dst_y))
931 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
935 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
939 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
943 void BlitTexture(Bitmap *bitmap,
944 int src_x, int src_y, int width, int height,
945 int dst_x, int dst_y)
950 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
954 void BlitTextureMasked(Bitmap *bitmap,
955 int src_x, int src_y, int width, int height,
956 int dst_x, int dst_y)
961 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
965 void BlitToScreen(Bitmap *bitmap,
966 int src_x, int src_y, int width, int height,
967 int dst_x, int dst_y)
972 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
973 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
974 width, height, dst_x, dst_y);
976 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
979 void BlitToScreenMasked(Bitmap *bitmap,
980 int src_x, int src_y, int width, int height,
981 int dst_x, int dst_y)
986 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
987 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
988 width, height, dst_x, dst_y);
990 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
993 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
996 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
999 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1000 int to_x, int to_y, Pixel pixel, int line_width)
1004 if (program.headless)
1007 for (x = 0; x < line_width; x++)
1009 for (y = 0; y < line_width; y++)
1011 int dx = x - line_width / 2;
1012 int dy = y - line_width / 2;
1014 if ((x == 0 && y == 0) ||
1015 (x == 0 && y == line_width - 1) ||
1016 (x == line_width - 1 && y == 0) ||
1017 (x == line_width - 1 && y == line_width - 1))
1021 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1026 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1031 for (i = 0; i < num_points - 1; i++)
1032 DrawLine(bitmap, points[i].x, points[i].y,
1033 points[i + 1].x, points[i + 1].y, pixel, line_width);
1036 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1040 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1042 if (program.headless)
1045 if (x < 0 || x >= bitmap->width ||
1046 y < 0 || y >= bitmap->height)
1049 return SDLGetPixel(bitmap, x, y);
1052 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1053 unsigned int color_g, unsigned int color_b)
1055 if (program.headless)
1058 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1061 void KeyboardAutoRepeatOn(void)
1063 keyrepeat_status = TRUE;
1066 void KeyboardAutoRepeatOff(void)
1068 keyrepeat_status = FALSE;
1071 boolean SetVideoMode(boolean fullscreen)
1073 return SDLSetVideoMode(fullscreen);
1076 void SetVideoFrameDelay(unsigned int frame_delay_value)
1078 video.frame_delay.value = frame_delay_value;
1081 unsigned int GetVideoFrameDelay(void)
1083 return video.frame_delay.value;
1086 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1088 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1089 (!fullscreen && video.fullscreen_enabled))
1090 fullscreen = SetVideoMode(fullscreen);
1095 Bitmap *LoadImage(char *filename)
1099 new_bitmap = SDLLoadImage(filename);
1102 new_bitmap->source_filename = getStringCopy(filename);
1107 Bitmap *LoadCustomImage(char *basename)
1109 char *filename = getCustomImageFilename(basename);
1112 if (filename == NULL)
1113 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1115 if ((new_bitmap = LoadImage(filename)) == NULL)
1116 Fail("LoadImage('%s') failed", basename);
1121 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1123 char *filename = getCustomImageFilename(basename);
1126 if (filename == NULL) // (should never happen)
1128 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1133 if (strEqual(filename, bitmap->source_filename))
1135 // The old and new image are the same (have the same filename and path).
1136 // This usually means that this image does not exist in this graphic set
1137 // and a fallback to the existing image is done.
1142 if ((new_bitmap = LoadImage(filename)) == NULL)
1144 Warn("LoadImage('%s') failed", basename);
1149 if (bitmap->width != new_bitmap->width ||
1150 bitmap->height != new_bitmap->height)
1152 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1155 FreeBitmap(new_bitmap);
1160 TransferBitmapPointers(new_bitmap, bitmap);
1164 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1166 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1169 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1171 if (bitmaps[IMG_BITMAP_CUSTOM])
1173 // check if original sized bitmap points to custom sized bitmap
1174 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] == bitmaps[IMG_BITMAP_CUSTOM])
1176 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1178 // keep pointer of previous custom size bitmap
1179 bitmaps[IMG_BITMAP_OTHER] = bitmaps[IMG_BITMAP_CUSTOM];
1181 // set original bitmap pointer to scaled original bitmap of other size
1182 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1184 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1188 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1191 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1194 if (gfx.game_tile_size == gfx.standard_tile_size)
1196 // set game bitmap pointer to standard sized bitmap (already existing)
1197 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1202 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1203 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1204 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1206 bitmaps[IMG_BITMAP_CUSTOM] = ZoomBitmap(bitmap, width, height);
1208 // set game bitmap pointer to custom sized bitmap (newly created)
1209 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1212 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1213 int tile_size, boolean create_small_bitmaps)
1215 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1216 Bitmap *tmp_bitmap_final = NULL;
1217 Bitmap *tmp_bitmap_0 = NULL;
1218 Bitmap *tmp_bitmap_1 = NULL;
1219 Bitmap *tmp_bitmap_2 = NULL;
1220 Bitmap *tmp_bitmap_4 = NULL;
1221 Bitmap *tmp_bitmap_8 = NULL;
1222 Bitmap *tmp_bitmap_16 = NULL;
1223 Bitmap *tmp_bitmap_32 = NULL;
1224 int width_final, height_final;
1225 int width_0, height_0;
1226 int width_1, height_1;
1227 int width_2, height_2;
1228 int width_4, height_4;
1229 int width_8, height_8;
1230 int width_16, height_16;
1231 int width_32, height_32;
1232 int old_width, old_height;
1235 print_timestamp_init("CreateScaledBitmaps");
1237 old_width = old_bitmap->width;
1238 old_height = old_bitmap->height;
1240 // calculate new image dimensions for final image size
1241 width_final = old_width * zoom_factor;
1242 height_final = old_height * zoom_factor;
1244 // get image with final size (this might require scaling up)
1245 // ("final" size may result in non-standard tile size image)
1246 if (zoom_factor != 1)
1247 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1249 tmp_bitmap_final = old_bitmap;
1251 UPDATE_BUSY_STATE();
1253 width_0 = width_1 = width_final;
1254 height_0 = height_1 = height_final;
1256 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1258 if (create_small_bitmaps)
1260 // check if we have a non-gameplay tile size image
1261 if (tile_size != gfx.game_tile_size)
1263 // get image with gameplay tile size
1264 width_0 = width_final * gfx.game_tile_size / tile_size;
1265 height_0 = height_final * gfx.game_tile_size / tile_size;
1267 if (width_0 == old_width)
1268 tmp_bitmap_0 = old_bitmap;
1269 else if (width_0 == width_final)
1270 tmp_bitmap_0 = tmp_bitmap_final;
1272 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1274 UPDATE_BUSY_STATE();
1277 // check if we have a non-standard tile size image
1278 if (tile_size != gfx.standard_tile_size)
1280 // get image with standard tile size
1281 width_1 = width_final * gfx.standard_tile_size / tile_size;
1282 height_1 = height_final * gfx.standard_tile_size / tile_size;
1284 if (width_1 == old_width)
1285 tmp_bitmap_1 = old_bitmap;
1286 else if (width_1 == width_final)
1287 tmp_bitmap_1 = tmp_bitmap_final;
1288 else if (width_1 == width_0)
1289 tmp_bitmap_1 = tmp_bitmap_0;
1291 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1293 UPDATE_BUSY_STATE();
1296 // calculate new image dimensions for small images
1297 width_2 = width_1 / 2;
1298 height_2 = height_1 / 2;
1299 width_4 = width_1 / 4;
1300 height_4 = height_1 / 4;
1301 width_8 = width_1 / 8;
1302 height_8 = height_1 / 8;
1303 width_16 = width_1 / 16;
1304 height_16 = height_1 / 16;
1305 width_32 = width_1 / 32;
1306 height_32 = height_1 / 32;
1308 // get image with 1/2 of normal size (for use in the level editor)
1309 if (width_2 == old_width)
1310 tmp_bitmap_2 = old_bitmap;
1312 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1314 UPDATE_BUSY_STATE();
1316 // get image with 1/4 of normal size (for use in the level editor)
1317 if (width_4 == old_width)
1318 tmp_bitmap_4 = old_bitmap;
1320 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1322 UPDATE_BUSY_STATE();
1324 // get image with 1/8 of normal size (for use on the preview screen)
1325 if (width_8 == old_width)
1326 tmp_bitmap_8 = old_bitmap;
1328 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1330 UPDATE_BUSY_STATE();
1332 // get image with 1/16 of normal size (for use on the preview screen)
1333 if (width_16 == old_width)
1334 tmp_bitmap_16 = old_bitmap;
1336 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1338 UPDATE_BUSY_STATE();
1340 // get image with 1/32 of normal size (for use on the preview screen)
1341 if (width_32 == old_width)
1342 tmp_bitmap_32 = old_bitmap;
1344 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1346 UPDATE_BUSY_STATE();
1348 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1349 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1350 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1351 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1352 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1353 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1355 if (width_0 != width_1)
1356 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1358 if (bitmaps[IMG_BITMAP_CUSTOM])
1359 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1361 bitmaps[IMG_BITMAP_PTR_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1363 // store the "final" (up-scaled) original bitmap, if not already stored
1365 int tmp_bitmap_final_nr = -1;
1367 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1368 if (bitmaps[i] == tmp_bitmap_final)
1369 tmp_bitmap_final_nr = i;
1371 if (tmp_bitmap_final_nr == -1) // scaled original bitmap not stored
1373 // store pointer of scaled original bitmap (not used for any other size)
1374 bitmaps[IMG_BITMAP_OTHER] = tmp_bitmap_final;
1376 // set original bitmap pointer to scaled original bitmap of other size
1377 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_OTHER];
1381 // set original bitmap pointer to corresponding sized bitmap
1382 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[tmp_bitmap_final_nr];
1385 // free the "old" (unscaled) original bitmap, if not already stored
1387 boolean free_old_bitmap = TRUE;
1389 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1390 if (bitmaps[i] == old_bitmap)
1391 free_old_bitmap = FALSE;
1393 if (free_old_bitmap)
1395 // copy image filename from old to new standard sized bitmap
1396 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1397 getStringCopy(old_bitmap->source_filename);
1399 FreeBitmap(old_bitmap);
1404 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1406 // set original bitmap pointer to corresponding sized bitmap
1407 bitmaps[IMG_BITMAP_PTR_ORIGINAL] = bitmaps[IMG_BITMAP_32x32];
1409 if (old_bitmap != tmp_bitmap_1)
1410 FreeBitmap(old_bitmap);
1413 UPDATE_BUSY_STATE();
1415 print_timestamp_done("CreateScaledBitmaps");
1418 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1421 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1424 void CreateBitmapTextures(Bitmap **bitmaps)
1426 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1427 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1429 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1432 void FreeBitmapTextures(Bitmap **bitmaps)
1434 if (bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL)
1435 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_PTR_ORIGINAL]);
1437 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1440 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1442 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1446 // ----------------------------------------------------------------------------
1447 // mouse pointer functions
1448 // ----------------------------------------------------------------------------
1450 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1452 // XPM image definitions
1453 static const char *cursor_image_none[] =
1455 // width height num_colors chars_per_pixel
1485 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1486 static const char *cursor_image_dot[] =
1488 // width height num_colors chars_per_pixel
1517 static const char **cursor_image_playfield = cursor_image_dot;
1519 // some people complained about a "white dot" on the screen and thought it
1520 // was a graphical error... OK, let's just remove the whole pointer :-)
1521 static const char **cursor_image_playfield = cursor_image_none;
1524 static const int cursor_bit_order = BIT_ORDER_MSB;
1526 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1528 struct MouseCursorInfo *cursor;
1529 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1530 int header_lines = 4;
1533 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1535 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1538 for (y = 0; y < cursor->width; y++)
1540 for (x = 0; x < cursor->height; x++)
1543 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1548 cursor->data[i] = cursor->mask[i] = 0;
1551 switch (image[header_lines + y][x])
1554 cursor->data[i] |= bit_mask;
1555 cursor->mask[i] |= bit_mask;
1559 cursor->mask[i] |= bit_mask;
1568 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1573 void SetMouseCursor(int mode)
1575 static struct MouseCursorInfo *cursor_none = NULL;
1576 static struct MouseCursorInfo *cursor_playfield = NULL;
1577 struct MouseCursorInfo *cursor_new;
1578 int mode_final = mode;
1580 if (cursor_none == NULL)
1581 cursor_none = get_cursor_from_image(cursor_image_none);
1583 if (cursor_playfield == NULL)
1584 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1586 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1587 mode_final = gfx.cursor_mode_override;
1589 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1590 mode_final == CURSOR_NONE ? cursor_none :
1591 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1593 SDLSetMouseCursor(cursor_new);
1595 gfx.cursor_mode = mode;
1596 gfx.cursor_mode_final = mode_final;
1599 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1601 // mouse events do not contain logical screen size corrections yet
1602 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1604 mouse_x -= video.screen_xoffset;
1605 mouse_y -= video.screen_yoffset;
1607 gfx.mouse_x = mouse_x;
1608 gfx.mouse_y = mouse_y;
1611 void UpdateMousePosition(void)
1613 int mouse_x, mouse_y;
1616 SDL_GetMouseState(&mouse_x, &mouse_y);
1618 UpdateRawMousePosition(mouse_x, mouse_y);
1622 // ============================================================================
1624 // ============================================================================
1626 void OpenAudio(void)
1628 // always start with reliable default values
1629 audio.sound_available = FALSE;
1630 audio.music_available = FALSE;
1631 audio.loops_available = FALSE;
1633 audio.sound_enabled = FALSE;
1634 audio.sound_deactivated = FALSE;
1636 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1637 audio.mixer_pid = 0;
1638 audio.device_name = NULL;
1639 audio.device_fd = -1;
1641 audio.num_channels = 0;
1642 audio.music_channel = 0;
1643 audio.first_sound_channel = 0;
1648 void CloseAudio(void)
1652 audio.sound_enabled = FALSE;
1655 void SetAudioMode(boolean enabled)
1657 if (!audio.sound_available)
1660 audio.sound_enabled = enabled;
1664 // ============================================================================
1666 // ============================================================================
1668 void InitEventFilter(EventFilter filter_function)
1670 SDL_SetEventFilter(filter_function, NULL);
1673 boolean PendingEvent(void)
1675 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1678 void WaitEvent(Event *event)
1680 SDLWaitEvent(event);
1683 void PeekEvent(Event *event)
1685 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1688 void PumpEvents(void)
1693 void CheckQuitEvent(void)
1695 if (SDL_QuitRequested())
1696 program.exit_function(0);
1699 Key GetEventKey(KeyEvent *event)
1701 // key up/down events in SDL2 do not return text characters anymore
1702 return event->keysym.sym;
1705 KeyMod HandleKeyModState(Key key, int key_status)
1707 static KeyMod current_modifiers = KMOD_None;
1709 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1711 KeyMod new_modifier = KMOD_None;
1716 new_modifier = KMOD_Shift_L;
1719 new_modifier = KMOD_Shift_R;
1721 case KSYM_Control_L:
1722 new_modifier = KMOD_Control_L;
1724 case KSYM_Control_R:
1725 new_modifier = KMOD_Control_R;
1728 new_modifier = KMOD_Meta_L;
1731 new_modifier = KMOD_Meta_R;
1734 new_modifier = KMOD_Alt_L;
1737 new_modifier = KMOD_Alt_R;
1743 if (key_status == KEY_PRESSED)
1744 current_modifiers |= new_modifier;
1746 current_modifiers &= ~new_modifier;
1749 return current_modifiers;
1752 KeyMod GetKeyModState(void)
1754 return (KeyMod)SDL_GetModState();
1757 KeyMod GetKeyModStateFromEvents(void)
1759 /* always use key modifier state as tracked from key events (this is needed
1760 if the modifier key event was injected into the event queue, but the key
1761 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1762 query the keys as held pressed on the keyboard) -- this case is currently
1763 only used to filter out clipboard insert events from "True X-Mouse" tool */
1765 return HandleKeyModState(KSYM_UNDEFINED, 0);
1768 void StartTextInput(int x, int y, int width, int height)
1770 textinput_status = TRUE;
1772 #if defined(HAS_SCREEN_KEYBOARD)
1773 SDL_StartTextInput();
1775 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1777 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1778 video.shifted_up_delay.count = SDL_GetTicks();
1779 video.shifted_up = TRUE;
1784 void StopTextInput(void)
1786 textinput_status = FALSE;
1788 #if defined(HAS_SCREEN_KEYBOARD)
1789 SDL_StopTextInput();
1791 if (video.shifted_up)
1793 video.shifted_up_pos = 0;
1794 video.shifted_up_delay.count = SDL_GetTicks();
1795 video.shifted_up = FALSE;
1800 void PushUserEvent(int code, int value1, int value2)
1804 SDL_memset(&event, 0, sizeof(event));
1806 event.type = EVENT_USER;
1808 event.value1 = value1;
1809 event.value2 = value2;
1811 SDL_PushEvent((SDL_Event *)&event);
1814 boolean PendingEscapeKeyEvent(void)
1820 // check if any key press event is pending
1821 if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
1824 // check if pressed key is "Escape" key
1825 if (event.key.keysym.sym == KSYM_Escape)
1833 // ============================================================================
1834 // joystick functions
1835 // ============================================================================
1837 void InitJoysticks(void)
1841 #if defined(NO_JOYSTICK)
1842 return; // joysticks generally deactivated by compile-time directive
1845 // always start with reliable default values
1846 joystick.status = JOYSTICK_NOT_AVAILABLE;
1847 for (i = 0; i < MAX_PLAYERS; i++)
1848 joystick.nr[i] = -1; // no joystick configured
1853 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1855 return SDLReadJoystick(nr, x, y, b1, b2);
1858 boolean CheckJoystickOpened(int nr)
1860 return SDLCheckJoystickOpened(nr);
1863 void ClearJoystickState(void)
1865 SDLClearJoystickState();
1869 // ============================================================================
1870 // Emscripten functions
1871 // ============================================================================
1873 void InitEmscriptenFilesystem(void)
1875 #if defined(PLATFORM_EMSCRIPTEN)
1878 dir = UTF8ToString($0);
1880 Module.sync_done = 0;
1882 FS.mkdir(dir); // create persistent data directory
1883 FS.mount(IDBFS, {}, dir); // mount with IDBFS filesystem type
1884 FS.syncfs(true, function(err) // sync persistent data into memory
1887 Module.sync_done = 1;
1889 }, PERSISTENT_DIRECTORY);
1891 // wait for persistent data to be synchronized to memory
1892 while (emscripten_run_script_int("Module.sync_done") == 0)
1897 void SyncEmscriptenFilesystem(void)
1899 #if defined(PLATFORM_EMSCRIPTEN)
1902 FS.syncfs(function(err)