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.headless = FALSE;
108 #if defined(PLATFORM_EMSCRIPTEN)
111 Module.sync_done = 0;
113 FS.mkdir('/persistent'); // create persistent data directory
114 FS.mount(IDBFS, {}, '/persistent'); // mount with IDBFS filesystem type
115 FS.syncfs(true, function(err) // sync persistent data into memory
118 Module.sync_done = 1;
122 // wait for persistent data to be synchronized to memory
123 while (emscripten_run_script_int("Module.sync_done") == 0)
128 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
129 char *server_host, int server_port)
131 network.enabled = enabled;
132 network.connected = connected;
133 network.serveronly = serveronly;
135 network.server_host = server_host;
136 network.server_port = server_port;
138 network.server_thread = NULL;
139 network.is_server_thread = FALSE;
142 void InitRuntimeInfo()
144 #if defined(HAS_TOUCH_DEVICE)
145 runtime.uses_touch_device = TRUE;
147 runtime.uses_touch_device = FALSE;
151 void InitScoresInfo(void)
153 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
155 program.global_scores = directoryExists(global_scores_dir);
156 program.many_scores_per_name = !program.global_scores;
161 if (program.global_scores)
163 Debug("internal:path", "Using global, multi-user scores directory '%s'.",
165 Debug("internal:path", "Remove to enable single-user scores directory.");
166 Debug("internal:path", "(This enables multipe score entries per user.)");
170 Debug("internal:path", "Using private, single-user scores directory.");
175 free(global_scores_dir);
178 void SetWindowTitle(void)
180 program.window_title = program.window_title_function();
185 void InitWindowTitleFunction(char *(*window_title_function)(void))
187 program.window_title_function = window_title_function;
190 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
192 program.exit_message_function = exit_message_function;
195 void InitExitFunction(void (*exit_function)(int))
197 program.exit_function = exit_function;
199 // set signal handlers to custom exit function
200 // signal(SIGINT, exit_function);
201 signal(SIGTERM, exit_function);
203 // set exit function to automatically cleanup SDL stuff after exit()
207 void InitPlatformDependentStuff(void)
209 // this is initialized in GetOptions(), but may already be used before
210 options.verbose = TRUE;
214 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
216 if (SDL_Init(sdl_init_flags) < 0)
217 Fail("SDL_Init() failed: %s", SDL_GetError());
222 void ClosePlatformDependentStuff(void)
227 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
228 int real_sx, int real_sy,
229 int full_sxsize, int full_sysize,
230 Bitmap *field_save_buffer)
236 gfx.real_sx = real_sx;
237 gfx.real_sy = real_sy;
238 gfx.full_sxsize = full_sxsize;
239 gfx.full_sysize = full_sysize;
241 gfx.field_save_buffer = field_save_buffer;
243 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
244 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
247 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
249 gfx.game_tile_size = game_tile_size;
250 gfx.standard_tile_size = standard_tile_size;
253 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
261 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
269 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
277 void InitGfxWindowInfo(int win_xsize, int win_ysize)
279 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
281 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
283 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
285 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
286 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
287 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
288 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
290 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
293 gfx.win_xsize = win_xsize;
294 gfx.win_ysize = win_ysize;
296 gfx.background_bitmap_mask = REDRAW_NONE;
299 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
301 // currently only used by MSDOS code to alloc VRAM buffer, if available
302 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
303 gfx.scrollbuffer_width = scrollbuffer_width;
304 gfx.scrollbuffer_height = scrollbuffer_height;
307 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
309 gfx.clipping_enabled = enabled;
312 gfx.clip_width = width;
313 gfx.clip_height = height;
316 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
318 gfx.draw_busy_anim_function = draw_busy_anim_function;
321 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
323 gfx.draw_global_anim_function = draw_global_anim_function;
326 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
328 gfx.draw_global_border_function = draw_global_border_function;
331 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
333 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
336 void InitGfxCustomArtworkInfo(void)
338 gfx.override_level_graphics = FALSE;
339 gfx.override_level_sounds = FALSE;
340 gfx.override_level_music = FALSE;
342 gfx.draw_init_text = TRUE;
345 void InitGfxOtherSettings(void)
347 gfx.cursor_mode = CURSOR_DEFAULT;
348 gfx.cursor_mode_override = CURSOR_UNDEFINED;
349 gfx.cursor_mode_final = gfx.cursor_mode;
351 // prevent initially displaying custom mouse cursor in upper left corner
352 gfx.mouse_x = POS_OFFSCREEN;
353 gfx.mouse_y = POS_OFFSCREEN;
356 void InitTileCursorInfo(void)
358 tile_cursor.enabled = FALSE;
359 tile_cursor.active = FALSE;
360 tile_cursor.moving = FALSE;
362 tile_cursor.xpos = 0;
363 tile_cursor.ypos = 0;
366 tile_cursor.target_x = 0;
367 tile_cursor.target_y = 0;
372 tile_cursor.xsn_debug = FALSE;
375 void InitOverlayInfo(void)
377 overlay.enabled = FALSE;
378 overlay.active = FALSE;
380 overlay.show_grid = FALSE;
382 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
383 overlay.grid_button_action = JOY_NO_ACTION;
385 SetOverlayGridSizeAndButtons();
387 #if defined(USE_TOUCH_INPUT_OVERLAY)
388 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
389 overlay.enabled = TRUE;
393 void SetOverlayGridSizeAndButtons(void)
395 int nr = GRID_ACTIVE_NR();
398 overlay.grid_xsize = setup.touch.grid_xsize[nr];
399 overlay.grid_ysize = setup.touch.grid_ysize[nr];
401 for (x = 0; x < MAX_GRID_XSIZE; x++)
402 for (y = 0; y < MAX_GRID_YSIZE; y++)
403 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
406 void SetTileCursorEnabled(boolean enabled)
408 tile_cursor.enabled = enabled;
411 void SetTileCursorActive(boolean active)
413 tile_cursor.active = active;
416 void SetTileCursorTargetXY(int x, int y)
418 // delayed placement of tile selection cursor at target position
419 // (tile cursor will be moved to target position step by step)
421 tile_cursor.xpos = x;
422 tile_cursor.ypos = y;
423 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
424 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
426 tile_cursor.moving = TRUE;
429 void SetTileCursorXY(int x, int y)
431 // immediate placement of tile selection cursor at target position
433 SetTileCursorTargetXY(x, y);
435 tile_cursor.x = tile_cursor.target_x;
436 tile_cursor.y = tile_cursor.target_y;
438 tile_cursor.moving = FALSE;
441 void SetTileCursorSXSY(int sx, int sy)
447 void SetOverlayEnabled(boolean enabled)
449 overlay.enabled = enabled;
452 void SetOverlayActive(boolean active)
454 overlay.active = active;
457 void SetOverlayShowGrid(boolean show_grid)
459 overlay.show_grid = show_grid;
461 SetOverlayActive(show_grid);
464 SetOverlayEnabled(TRUE);
467 boolean GetOverlayEnabled(void)
469 return overlay.enabled;
472 boolean GetOverlayActive(void)
474 return overlay.active;
477 void SetDrawDeactivationMask(int draw_deactivation_mask)
479 gfx.draw_deactivation_mask = draw_deactivation_mask;
482 int GetDrawDeactivationMask(void)
484 return gfx.draw_deactivation_mask;
487 void SetDrawBackgroundMask(int draw_background_mask)
489 gfx.draw_background_mask = draw_background_mask;
492 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
494 if (background_bitmap_tile != NULL)
495 gfx.background_bitmap_mask |= mask;
497 gfx.background_bitmap_mask &= ~mask;
499 if (background_bitmap_tile == NULL) // empty background requested
502 if (mask == REDRAW_ALL)
503 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
504 0, 0, video.width, video.height);
505 else if (mask == REDRAW_FIELD)
506 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
507 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
508 else if (mask == REDRAW_DOOR_1)
509 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
510 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
513 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
515 // remove every mask before setting mask for window
516 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
517 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
518 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
521 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
523 // remove window area mask before setting mask for main area
524 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
525 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
526 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
529 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
531 // remove window area mask before setting mask for door area
532 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
533 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
534 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
538 // ============================================================================
540 // ============================================================================
542 static int GetRealDepth(int depth)
544 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
547 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
548 int width, int height, Pixel color)
550 SDLFillRectangle(bitmap, x, y, width, height, color);
552 if (bitmap == backbuffer)
553 SetRedrawMaskFromArea(x, y, width, height);
556 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
557 int src_x, int src_y, int width, int height,
558 int dst_x, int dst_y, int mask_mode)
560 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
561 dst_x, dst_y, mask_mode);
563 if (dst_bitmap == backbuffer)
564 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
567 void LimitScreenUpdates(boolean enable)
569 SDLLimitScreenUpdates(enable);
572 void InitVideoDefaults(void)
574 video.default_depth = 32;
577 void InitVideoDisplay(void)
579 if (program.headless)
582 SDLInitVideoDisplay();
586 void CloseVideoDisplay(void)
588 KeyboardAutoRepeatOn();
590 SDL_QuitSubSystem(SDL_INIT_VIDEO);
593 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
596 video.height = height;
597 video.depth = GetRealDepth(depth);
599 video.screen_width = width;
600 video.screen_height = height;
601 video.screen_xoffset = 0;
602 video.screen_yoffset = 0;
604 video.fullscreen_available = FULLSCREEN_STATUS;
605 video.fullscreen_enabled = FALSE;
607 video.window_scaling_available = WINDOW_SCALING_STATUS;
609 video.frame_counter = 0;
610 video.frame_delay = 0;
611 video.frame_delay_value = GAME_FRAME_DELAY;
613 video.shifted_up = FALSE;
614 video.shifted_up_pos = 0;
615 video.shifted_up_pos_last = 0;
616 video.shifted_up_delay = 0;
617 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
619 SDLInitVideoBuffer(fullscreen);
621 video.initialized = !program.headless;
626 static void FreeBitmapPointers(Bitmap *bitmap)
631 SDLFreeBitmapPointers(bitmap);
633 checked_free(bitmap->source_filename);
634 bitmap->source_filename = NULL;
637 static void TransferBitmapPointers(Bitmap *src_bitmap,
640 if (src_bitmap == NULL || dst_bitmap == NULL)
643 FreeBitmapPointers(dst_bitmap);
645 *dst_bitmap = *src_bitmap;
648 void FreeBitmap(Bitmap *bitmap)
653 FreeBitmapPointers(bitmap);
658 Bitmap *CreateBitmapStruct(void)
660 return checked_calloc(sizeof(Bitmap));
663 Bitmap *CreateBitmap(int width, int height, int depth)
665 Bitmap *new_bitmap = CreateBitmapStruct();
666 int real_width = MAX(1, width); // prevent zero bitmap width
667 int real_height = MAX(1, height); // prevent zero bitmap height
668 int real_depth = GetRealDepth(depth);
670 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
672 new_bitmap->width = real_width;
673 new_bitmap->height = real_height;
678 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
682 // if new bitmap size fits into old one, no need to re-create it
683 if (width <= (*bitmap)->width &&
684 height <= (*bitmap)->height)
687 // else adjust size so that old and new bitmap size fit into it
688 width = MAX(width, (*bitmap)->width);
689 height = MAX(height, (*bitmap)->height);
692 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
696 *bitmap = new_bitmap;
700 TransferBitmapPointers(new_bitmap, *bitmap);
706 static void CloseWindow(DrawWindow *window)
711 void SetRedrawMaskFromArea(int x, int y, int width, int height)
715 int x2 = x + width - 1;
716 int y2 = y + height - 1;
718 if (width == 0 || height == 0)
721 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
722 redraw_mask |= REDRAW_FIELD;
723 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
724 redraw_mask |= REDRAW_DOOR_1;
725 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
726 redraw_mask |= REDRAW_DOOR_2;
727 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
728 redraw_mask |= REDRAW_DOOR_3;
730 redraw_mask = REDRAW_ALL;
733 static boolean CheckDrawingArea(int x, int y, int width, int height,
736 if (draw_mask == REDRAW_NONE)
739 if (draw_mask & REDRAW_ALL)
742 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
745 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
748 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
751 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
757 boolean DrawingDeactivatedField(void)
759 if (program.headless)
762 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
768 boolean DrawingDeactivated(int x, int y, int width, int height)
770 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
773 boolean DrawingOnBackground(int x, int y)
775 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
776 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
779 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
780 int *width, int *height, boolean is_dest)
782 int clip_x, clip_y, clip_width, clip_height;
784 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
786 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
787 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
788 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
789 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
795 clip_width = bitmap->width;
796 clip_height = bitmap->height;
799 // skip if rectangle completely outside bitmap
801 if (*x + *width <= clip_x ||
802 *y + *height <= clip_y ||
803 *x >= clip_x + clip_width ||
804 *y >= clip_y + clip_height)
807 // clip if rectangle overlaps bitmap
811 *width -= clip_x - *x;
814 else if (*x + *width > clip_x + clip_width)
816 *width = clip_x + clip_width - *x;
821 *height -= clip_y - *y;
824 else if (*y + *height > clip_y + clip_height)
826 *height = clip_y + clip_height - *y;
832 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
833 int src_x, int src_y, int width, int height,
834 int dst_x, int dst_y)
836 int dst_x_unclipped = dst_x;
837 int dst_y_unclipped = dst_y;
839 if (program.headless)
842 if (src_bitmap == NULL || dst_bitmap == NULL)
845 if (DrawingDeactivated(dst_x, dst_y, width, height))
848 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
849 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
852 // source x/y might need adjustment if destination x/y was clipped top/left
853 src_x += dst_x - dst_x_unclipped;
854 src_y += dst_y - dst_y_unclipped;
856 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
857 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
858 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
859 but is already fixed in SVN and should therefore finally be fixed with
860 the next official SDL release, which is probably version 1.2.14.) */
861 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
863 if (src_bitmap == dst_bitmap)
865 // needed when blitting directly to same bitmap -- should not be needed with
866 // recent SDL libraries, but apparently does not work in 1.2.11 directly
868 static Bitmap *tmp_bitmap = NULL;
869 static int tmp_bitmap_xsize = 0;
870 static int tmp_bitmap_ysize = 0;
872 // start with largest static bitmaps for initial bitmap size ...
873 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
875 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
876 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
879 // ... and allow for later re-adjustments due to custom artwork bitmaps
880 if (src_bitmap->width > tmp_bitmap_xsize ||
881 src_bitmap->height > tmp_bitmap_ysize)
883 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
884 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
886 FreeBitmap(tmp_bitmap);
891 if (tmp_bitmap == NULL)
892 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
895 sysCopyArea(src_bitmap, tmp_bitmap,
896 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
897 sysCopyArea(tmp_bitmap, dst_bitmap,
898 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
903 sysCopyArea(src_bitmap, dst_bitmap,
904 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
907 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
908 int src_x, int src_y, int src_width, int src_height,
909 int dst_x, int dst_y, int dst_width, int dst_height)
911 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
912 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
913 int dst_xsize = dst_width;
914 int dst_ysize = dst_height;
915 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
916 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
919 for (y = 0; y < src_ysteps; y++)
921 for (x = 0; x < src_xsteps; x++)
923 int draw_x = dst_x + x * src_xsize;
924 int draw_y = dst_y + y * src_ysize;
925 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
926 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
928 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
934 void FadeRectangle(int x, int y, int width, int height,
935 int fade_mode, int fade_delay, int post_delay,
936 void (*draw_border_function)(void))
938 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
939 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
942 SDLFadeRectangle(x, y, width, height,
943 fade_mode, fade_delay, post_delay, draw_border_function);
946 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
949 if (DrawingDeactivated(x, y, width, height))
952 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
955 sysFillRectangle(bitmap, x, y, width, height, color);
958 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
960 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
963 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
964 int width, int height)
966 if (DrawingOnBackground(x, y))
967 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
969 ClearRectangle(bitmap, x, y, width, height);
972 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
973 int src_x, int src_y, int width, int height,
974 int dst_x, int dst_y)
976 if (DrawingDeactivated(dst_x, dst_y, width, height))
979 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
980 dst_x, dst_y, BLIT_MASKED);
983 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
984 int src_x, int src_y, int width, int height,
985 int dst_x, int dst_y)
987 if (DrawingOnBackground(dst_x, dst_y))
990 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
994 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
998 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
1002 void BlitTexture(Bitmap *bitmap,
1003 int src_x, int src_y, int width, int height,
1004 int dst_x, int dst_y)
1009 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1013 void BlitTextureMasked(Bitmap *bitmap,
1014 int src_x, int src_y, int width, int height,
1015 int dst_x, int dst_y)
1020 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1024 void BlitToScreen(Bitmap *bitmap,
1025 int src_x, int src_y, int width, int height,
1026 int dst_x, int dst_y)
1031 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1032 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1033 width, height, dst_x, dst_y);
1035 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1038 void BlitToScreenMasked(Bitmap *bitmap,
1039 int src_x, int src_y, int width, int height,
1040 int dst_x, int dst_y)
1045 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1046 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1047 width, height, dst_x, dst_y);
1049 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1052 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1055 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1058 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1061 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1064 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1065 int to_x, int to_y, Pixel pixel, int line_width)
1069 if (program.headless)
1072 for (x = 0; x < line_width; x++)
1074 for (y = 0; y < line_width; y++)
1076 int dx = x - line_width / 2;
1077 int dy = y - line_width / 2;
1079 if ((x == 0 && y == 0) ||
1080 (x == 0 && y == line_width - 1) ||
1081 (x == line_width - 1 && y == 0) ||
1082 (x == line_width - 1 && y == line_width - 1))
1086 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1091 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1096 for (i = 0; i < num_points - 1; i++)
1097 DrawLine(bitmap, points[i].x, points[i].y,
1098 points[i + 1].x, points[i + 1].y, pixel, line_width);
1101 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1105 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1107 if (program.headless)
1110 if (x < 0 || x >= bitmap->width ||
1111 y < 0 || y >= bitmap->height)
1114 return SDLGetPixel(bitmap, x, y);
1117 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1118 unsigned int color_g, unsigned int color_b)
1120 if (program.headless)
1123 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1126 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1128 unsigned int color_r = (color >> 16) & 0xff;
1129 unsigned int color_g = (color >> 8) & 0xff;
1130 unsigned int color_b = (color >> 0) & 0xff;
1132 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1135 void KeyboardAutoRepeatOn(void)
1137 keyrepeat_status = TRUE;
1140 void KeyboardAutoRepeatOff(void)
1142 keyrepeat_status = FALSE;
1145 boolean SetVideoMode(boolean fullscreen)
1147 return SDLSetVideoMode(fullscreen);
1150 void SetVideoFrameDelay(unsigned int frame_delay_value)
1152 video.frame_delay_value = frame_delay_value;
1155 unsigned int GetVideoFrameDelay(void)
1157 return video.frame_delay_value;
1160 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1162 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1163 (!fullscreen && video.fullscreen_enabled))
1164 fullscreen = SetVideoMode(fullscreen);
1169 Bitmap *LoadImage(char *filename)
1173 new_bitmap = SDLLoadImage(filename);
1176 new_bitmap->source_filename = getStringCopy(filename);
1181 Bitmap *LoadCustomImage(char *basename)
1183 char *filename = getCustomImageFilename(basename);
1186 if (filename == NULL)
1187 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1189 if ((new_bitmap = LoadImage(filename)) == NULL)
1190 Fail("LoadImage('%s') failed", basename);
1195 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1197 char *filename = getCustomImageFilename(basename);
1200 if (filename == NULL) // (should never happen)
1202 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1207 if (strEqual(filename, bitmap->source_filename))
1209 // The old and new image are the same (have the same filename and path).
1210 // This usually means that this image does not exist in this graphic set
1211 // and a fallback to the existing image is done.
1216 if ((new_bitmap = LoadImage(filename)) == NULL)
1218 Warn("LoadImage('%s') failed", basename);
1223 if (bitmap->width != new_bitmap->width ||
1224 bitmap->height != new_bitmap->height)
1226 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1229 FreeBitmap(new_bitmap);
1234 TransferBitmapPointers(new_bitmap, bitmap);
1238 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1240 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1243 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1245 if (bitmaps[IMG_BITMAP_CUSTOM])
1247 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1249 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1252 if (gfx.game_tile_size == gfx.standard_tile_size)
1254 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1259 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1260 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1261 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1263 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1265 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1266 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1269 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1270 int tile_size, boolean create_small_bitmaps)
1272 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1273 Bitmap *tmp_bitmap_final = NULL;
1274 Bitmap *tmp_bitmap_0 = NULL;
1275 Bitmap *tmp_bitmap_1 = NULL;
1276 Bitmap *tmp_bitmap_2 = NULL;
1277 Bitmap *tmp_bitmap_4 = NULL;
1278 Bitmap *tmp_bitmap_8 = NULL;
1279 Bitmap *tmp_bitmap_16 = NULL;
1280 Bitmap *tmp_bitmap_32 = NULL;
1281 int width_final, height_final;
1282 int width_0, height_0;
1283 int width_1, height_1;
1284 int width_2, height_2;
1285 int width_4, height_4;
1286 int width_8, height_8;
1287 int width_16, height_16;
1288 int width_32, height_32;
1289 int old_width, old_height;
1292 print_timestamp_init("CreateScaledBitmaps");
1294 old_width = old_bitmap->width;
1295 old_height = old_bitmap->height;
1297 // calculate new image dimensions for final image size
1298 width_final = old_width * zoom_factor;
1299 height_final = old_height * zoom_factor;
1301 // get image with final size (this might require scaling up)
1302 // ("final" size may result in non-standard tile size image)
1303 if (zoom_factor != 1)
1304 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1306 tmp_bitmap_final = old_bitmap;
1308 UPDATE_BUSY_STATE();
1310 width_0 = width_1 = width_final;
1311 height_0 = height_1 = height_final;
1313 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1315 if (create_small_bitmaps)
1317 // check if we have a non-gameplay tile size image
1318 if (tile_size != gfx.game_tile_size)
1320 // get image with gameplay tile size
1321 width_0 = width_final * gfx.game_tile_size / tile_size;
1322 height_0 = height_final * gfx.game_tile_size / tile_size;
1324 if (width_0 == old_width)
1325 tmp_bitmap_0 = old_bitmap;
1326 else if (width_0 == width_final)
1327 tmp_bitmap_0 = tmp_bitmap_final;
1329 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1331 UPDATE_BUSY_STATE();
1334 // check if we have a non-standard tile size image
1335 if (tile_size != gfx.standard_tile_size)
1337 // get image with standard tile size
1338 width_1 = width_final * gfx.standard_tile_size / tile_size;
1339 height_1 = height_final * gfx.standard_tile_size / tile_size;
1341 if (width_1 == old_width)
1342 tmp_bitmap_1 = old_bitmap;
1343 else if (width_1 == width_final)
1344 tmp_bitmap_1 = tmp_bitmap_final;
1345 else if (width_1 == width_0)
1346 tmp_bitmap_1 = tmp_bitmap_0;
1348 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1350 UPDATE_BUSY_STATE();
1353 // calculate new image dimensions for small images
1354 width_2 = width_1 / 2;
1355 height_2 = height_1 / 2;
1356 width_4 = width_1 / 4;
1357 height_4 = height_1 / 4;
1358 width_8 = width_1 / 8;
1359 height_8 = height_1 / 8;
1360 width_16 = width_1 / 16;
1361 height_16 = height_1 / 16;
1362 width_32 = width_1 / 32;
1363 height_32 = height_1 / 32;
1365 // get image with 1/2 of normal size (for use in the level editor)
1366 if (width_2 == old_width)
1367 tmp_bitmap_2 = old_bitmap;
1369 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1371 UPDATE_BUSY_STATE();
1373 // get image with 1/4 of normal size (for use in the level editor)
1374 if (width_4 == old_width)
1375 tmp_bitmap_4 = old_bitmap;
1377 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1379 UPDATE_BUSY_STATE();
1381 // get image with 1/8 of normal size (for use on the preview screen)
1382 if (width_8 == old_width)
1383 tmp_bitmap_8 = old_bitmap;
1385 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1387 UPDATE_BUSY_STATE();
1389 // get image with 1/16 of normal size (for use on the preview screen)
1390 if (width_16 == old_width)
1391 tmp_bitmap_16 = old_bitmap;
1393 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1395 UPDATE_BUSY_STATE();
1397 // get image with 1/32 of normal size (for use on the preview screen)
1398 if (width_32 == old_width)
1399 tmp_bitmap_32 = old_bitmap;
1401 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1403 UPDATE_BUSY_STATE();
1405 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1406 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1407 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1408 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1409 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1410 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1412 if (width_0 != width_1)
1413 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1415 if (bitmaps[IMG_BITMAP_CUSTOM])
1416 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1418 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1420 boolean free_old_bitmap = TRUE;
1422 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1423 if (bitmaps[i] == old_bitmap)
1424 free_old_bitmap = FALSE;
1426 if (free_old_bitmap)
1428 // copy image filename from old to new standard sized bitmap
1429 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1430 getStringCopy(old_bitmap->source_filename);
1432 FreeBitmap(old_bitmap);
1437 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1440 UPDATE_BUSY_STATE();
1442 print_timestamp_done("CreateScaledBitmaps");
1445 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1448 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1451 void CreateBitmapTextures(Bitmap **bitmaps)
1453 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1456 void FreeBitmapTextures(Bitmap **bitmaps)
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, boolean with_modifiers)
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 = 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 = 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);
1836 // ============================================================================
1837 // joystick functions
1838 // ============================================================================
1840 void InitJoysticks(void)
1844 #if defined(NO_JOYSTICK)
1845 return; // joysticks generally deactivated by compile-time directive
1848 // always start with reliable default values
1849 joystick.status = JOYSTICK_NOT_AVAILABLE;
1850 for (i = 0; i < MAX_PLAYERS; i++)
1851 joystick.nr[i] = -1; // no joystick configured
1856 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1858 return SDLReadJoystick(nr, x, y, b1, b2);
1861 boolean CheckJoystickOpened(int nr)
1863 return SDLCheckJoystickOpened(nr);
1866 void ClearJoystickState(void)
1868 SDLClearJoystickState();