1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct OptionInfo options;
34 struct VideoSystemInfo video;
35 struct AudioSystemInfo audio;
37 struct TileCursorInfo tile_cursor;
38 struct OverlayInfo overlay;
39 struct ArtworkInfo artwork;
40 struct JoystickInfo joystick;
41 struct SetupInfo setup;
43 LevelDirTree *leveldir_first_all = NULL;
44 LevelDirTree *leveldir_first = NULL;
45 LevelDirTree *leveldir_current = NULL;
48 struct LevelSetInfo levelset;
49 struct LevelStats level_stats[MAX_LEVELS];
51 DrawWindow *window = NULL;
52 DrawBuffer *backbuffer = NULL;
53 DrawBuffer *drawto = NULL;
55 int button_status = MB_NOT_PRESSED;
56 boolean motion_status = FALSE;
57 int wheel_steps = DEFAULT_WHEEL_STEPS;
58 #if defined(TARGET_SDL2)
59 boolean keyrepeat_status = TRUE;
62 int redraw_mask = REDRAW_NONE;
67 /* ========================================================================= */
68 /* init/close functions */
69 /* ========================================================================= */
71 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
72 char *program_title, char *icon_title,
73 char *icon_filename, char *cookie_prefix,
74 char *program_version_string, int program_version)
76 program.command_basepath = getBasePath(argv0);
77 program.command_basename = getBaseName(argv0);
79 program.config_filename = config_filename;
81 program.userdata_subdir = userdata_subdir;
82 program.userdata_path = getUserGameDataDir();
84 program.program_title = program_title;
85 program.window_title = "(undefined)";
86 program.icon_title = icon_title;
88 program.icon_filename = icon_filename;
90 program.cookie_prefix = cookie_prefix;
92 program.version_super = VERSION_SUPER(program_version);
93 program.version_major = VERSION_MAJOR(program_version);
94 program.version_minor = VERSION_MINOR(program_version);
95 program.version_patch = VERSION_PATCH(program_version);
96 program.version_ident = program_version;
98 program.version_string = program_version_string;
100 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
101 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
102 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
103 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
105 program.headless = FALSE;
108 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
109 char *server_host, int server_port)
111 network.enabled = enabled;
112 network.connected = connected;
113 network.serveronly = serveronly;
115 network.server_host = server_host;
116 network.server_port = server_port;
119 void InitScoresInfo()
121 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
123 program.global_scores = directoryExists(global_scores_dir);
124 program.many_scores_per_name = !program.global_scores;
129 if (program.global_scores)
131 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
133 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
134 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
138 Error(ERR_DEBUG, "Using private, single-user scores directory.");
143 free(global_scores_dir);
146 void SetWindowTitle()
148 program.window_title = program.window_title_function();
153 void InitWindowTitleFunction(char *(*window_title_function)(void))
155 program.window_title_function = window_title_function;
158 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
160 program.exit_message_function = exit_message_function;
163 void InitExitFunction(void (*exit_function)(int))
165 program.exit_function = exit_function;
167 /* set signal handlers to custom exit function */
168 // signal(SIGINT, exit_function);
169 signal(SIGTERM, exit_function);
171 /* set exit function to automatically cleanup SDL stuff after exit() */
175 void InitPlatformDependentStuff(void)
177 // this is initialized in GetOptions(), but may already be used before
178 options.verbose = TRUE;
182 #if defined(TARGET_SDL2)
183 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
185 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
188 if (SDL_Init(sdl_init_flags) < 0)
189 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
194 void ClosePlatformDependentStuff(void)
199 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
200 int real_sx, int real_sy,
201 int full_sxsize, int full_sysize,
202 Bitmap *field_save_buffer)
208 gfx.real_sx = real_sx;
209 gfx.real_sy = real_sy;
210 gfx.full_sxsize = full_sxsize;
211 gfx.full_sysize = full_sysize;
213 gfx.field_save_buffer = field_save_buffer;
215 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
216 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
219 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
221 gfx.game_tile_size = game_tile_size;
222 gfx.standard_tile_size = standard_tile_size;
225 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
233 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
241 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
249 void InitGfxWindowInfo(int win_xsize, int win_ysize)
251 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
253 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
255 #if defined(TARGET_SDL2)
256 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
259 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
260 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
261 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
262 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
264 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
267 gfx.win_xsize = win_xsize;
268 gfx.win_ysize = win_ysize;
270 gfx.background_bitmap_mask = REDRAW_NONE;
273 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
275 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
276 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
277 gfx.scrollbuffer_width = scrollbuffer_width;
278 gfx.scrollbuffer_height = scrollbuffer_height;
281 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
283 gfx.clipping_enabled = enabled;
286 gfx.clip_width = width;
287 gfx.clip_height = height;
290 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
292 gfx.draw_busy_anim_function = draw_busy_anim_function;
295 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
297 gfx.draw_global_anim_function = draw_global_anim_function;
300 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
302 gfx.draw_global_border_function = draw_global_border_function;
305 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
307 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
310 void InitGfxCustomArtworkInfo()
312 gfx.override_level_graphics = FALSE;
313 gfx.override_level_sounds = FALSE;
314 gfx.override_level_music = FALSE;
316 gfx.draw_init_text = TRUE;
319 void InitGfxOtherSettings()
321 gfx.cursor_mode = CURSOR_DEFAULT;
324 void InitTileCursorInfo()
326 tile_cursor.enabled = FALSE;
327 tile_cursor.active = FALSE;
328 tile_cursor.moving = FALSE;
330 tile_cursor.xpos = 0;
331 tile_cursor.ypos = 0;
334 tile_cursor.target_x = 0;
335 tile_cursor.target_y = 0;
341 void InitOverlayInfo()
343 int nr = GRID_ACTIVE_NR();
346 overlay.enabled = FALSE;
347 overlay.active = FALSE;
349 overlay.show_grid = FALSE;
351 overlay.grid_xsize = setup.touch.grid_xsize[nr];
352 overlay.grid_ysize = setup.touch.grid_ysize[nr];
354 for (x = 0; x < MAX_GRID_XSIZE; x++)
355 for (y = 0; y < MAX_GRID_YSIZE; y++)
356 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
358 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
359 overlay.grid_button_action = JOY_NO_ACTION;
361 #if defined(USE_TOUCH_INPUT_OVERLAY)
362 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
363 overlay.enabled = TRUE;
367 void SetTileCursorEnabled(boolean enabled)
369 tile_cursor.enabled = enabled;
372 void SetTileCursorActive(boolean active)
374 tile_cursor.active = active;
377 void SetTileCursorTargetXY(int x, int y)
379 // delayed placement of tile selection cursor at target position
380 // (tile cursor will be moved to target position step by step)
382 tile_cursor.xpos = x;
383 tile_cursor.ypos = y;
384 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
385 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
387 tile_cursor.moving = TRUE;
390 void SetTileCursorXY(int x, int y)
392 // immediate placement of tile selection cursor at target position
394 SetTileCursorTargetXY(x, y);
396 tile_cursor.x = tile_cursor.target_x;
397 tile_cursor.y = tile_cursor.target_y;
399 tile_cursor.moving = FALSE;
402 void SetTileCursorSXSY(int sx, int sy)
408 void SetOverlayEnabled(boolean enabled)
410 overlay.enabled = enabled;
413 void SetOverlayActive(boolean active)
415 overlay.active = active;
418 void SetOverlayShowGrid(boolean show_grid)
420 overlay.show_grid = show_grid;
422 SetOverlayActive(show_grid);
425 SetOverlayEnabled(TRUE);
428 boolean GetOverlayActive()
430 return overlay.active;
433 void SetDrawDeactivationMask(int draw_deactivation_mask)
435 gfx.draw_deactivation_mask = draw_deactivation_mask;
438 int GetDrawDeactivationMask()
440 return gfx.draw_deactivation_mask;
443 void SetDrawBackgroundMask(int draw_background_mask)
445 gfx.draw_background_mask = draw_background_mask;
448 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
450 if (background_bitmap_tile != NULL)
451 gfx.background_bitmap_mask |= mask;
453 gfx.background_bitmap_mask &= ~mask;
455 if (background_bitmap_tile == NULL) /* empty background requested */
458 if (mask == REDRAW_ALL)
459 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
460 0, 0, video.width, video.height);
461 else if (mask == REDRAW_FIELD)
462 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
463 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
464 else if (mask == REDRAW_DOOR_1)
465 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
466 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
469 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
471 /* remove every mask before setting mask for window */
472 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
473 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
474 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
477 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
479 /* remove window area mask before setting mask for main area */
480 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
481 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
482 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
485 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
487 /* remove window area mask before setting mask for door area */
488 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
489 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
490 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
494 /* ========================================================================= */
495 /* video functions */
496 /* ========================================================================= */
498 inline static int GetRealDepth(int depth)
500 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
503 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
504 int width, int height, Pixel color)
506 SDLFillRectangle(bitmap, x, y, width, height, color);
508 if (bitmap == backbuffer)
509 SetRedrawMaskFromArea(x, y, width, height);
512 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
513 int src_x, int src_y, int width, int height,
514 int dst_x, int dst_y, int mask_mode)
516 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
517 dst_x, dst_y, mask_mode);
519 if (dst_bitmap == backbuffer)
520 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
523 void LimitScreenUpdates(boolean enable)
525 SDLLimitScreenUpdates(enable);
528 void InitVideoDefaults(void)
530 video.default_depth = 32;
533 void InitVideoDisplay(void)
535 if (program.headless)
538 SDLInitVideoDisplay();
539 #if defined(TARGET_SDL2)
544 void CloseVideoDisplay(void)
546 KeyboardAutoRepeatOn();
548 SDL_QuitSubSystem(SDL_INIT_VIDEO);
551 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
554 video.height = height;
555 video.depth = GetRealDepth(depth);
557 video.screen_width = width;
558 video.screen_height = height;
559 video.screen_xoffset = 0;
560 video.screen_yoffset = 0;
562 video.fullscreen_available = FULLSCREEN_STATUS;
563 video.fullscreen_enabled = FALSE;
565 video.window_scaling_available = WINDOW_SCALING_STATUS;
567 video.frame_delay = 0;
568 video.frame_delay_value = GAME_FRAME_DELAY;
570 video.shifted_up = FALSE;
571 video.shifted_up_pos = 0;
572 video.shifted_up_pos_last = 0;
573 video.shifted_up_delay = 0;
574 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
576 SDLInitVideoBuffer(fullscreen);
578 video.initialized = !program.headless;
583 inline static void FreeBitmapPointers(Bitmap *bitmap)
588 SDLFreeBitmapPointers(bitmap);
590 checked_free(bitmap->source_filename);
591 bitmap->source_filename = NULL;
594 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
597 if (src_bitmap == NULL || dst_bitmap == NULL)
600 FreeBitmapPointers(dst_bitmap);
602 *dst_bitmap = *src_bitmap;
605 void FreeBitmap(Bitmap *bitmap)
610 FreeBitmapPointers(bitmap);
615 Bitmap *CreateBitmapStruct(void)
617 return checked_calloc(sizeof(Bitmap));
620 Bitmap *CreateBitmap(int width, int height, int depth)
622 Bitmap *new_bitmap = CreateBitmapStruct();
623 int real_width = MAX(1, width); /* prevent zero bitmap width */
624 int real_height = MAX(1, height); /* prevent zero bitmap height */
625 int real_depth = GetRealDepth(depth);
627 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
629 new_bitmap->width = real_width;
630 new_bitmap->height = real_height;
635 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
639 /* if new bitmap size fits into old one, no need to re-create it */
640 if (width <= (*bitmap)->width &&
641 height <= (*bitmap)->height)
644 /* else adjust size so that old and new bitmap size fit into it */
645 width = MAX(width, (*bitmap)->width);
646 height = MAX(height, (*bitmap)->height);
649 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
653 *bitmap = new_bitmap;
657 TransferBitmapPointers(new_bitmap, *bitmap);
662 void CloseWindow(DrawWindow *window)
666 void SetRedrawMaskFromArea(int x, int y, int width, int height)
670 int x2 = x + width - 1;
671 int y2 = y + height - 1;
673 if (width == 0 || height == 0)
676 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
677 redraw_mask |= REDRAW_FIELD;
678 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
679 redraw_mask |= REDRAW_DOOR_1;
680 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
681 redraw_mask |= REDRAW_DOOR_2;
682 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
683 redraw_mask |= REDRAW_DOOR_3;
685 redraw_mask = REDRAW_ALL;
688 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
691 if (draw_mask == REDRAW_NONE)
694 if (draw_mask & REDRAW_ALL)
697 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
700 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
703 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
706 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
712 boolean DrawingDeactivatedField()
714 if (program.headless)
717 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
723 boolean DrawingDeactivated(int x, int y, int width, int height)
725 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
728 boolean DrawingOnBackground(int x, int y)
730 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
731 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
734 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
735 int *width, int *height, boolean is_dest)
737 int clip_x, clip_y, clip_width, clip_height;
739 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
741 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
742 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
743 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
744 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
750 clip_width = bitmap->width;
751 clip_height = bitmap->height;
754 /* skip if rectangle completely outside bitmap */
756 if (*x + *width <= clip_x ||
757 *y + *height <= clip_y ||
758 *x >= clip_x + clip_width ||
759 *y >= clip_y + clip_height)
762 /* clip if rectangle overlaps bitmap */
766 *width -= clip_x - *x;
769 else if (*x + *width > clip_x + clip_width)
771 *width = clip_x + clip_width - *x;
776 *height -= clip_y - *y;
779 else if (*y + *height > clip_y + clip_height)
781 *height = clip_y + clip_height - *y;
787 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
788 int src_x, int src_y, int width, int height,
789 int dst_x, int dst_y)
791 int dst_x_unclipped = dst_x;
792 int dst_y_unclipped = dst_y;
794 if (program.headless)
797 if (src_bitmap == NULL || dst_bitmap == NULL)
800 if (DrawingDeactivated(dst_x, dst_y, width, height))
803 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
804 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
807 /* source x/y might need adjustment if destination x/y was clipped top/left */
808 src_x += dst_x - dst_x_unclipped;
809 src_y += dst_y - dst_y_unclipped;
811 #if defined(TARGET_SDL2)
812 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
813 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
814 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
815 but is already fixed in SVN and should therefore finally be fixed with
816 the next official SDL release, which is probably version 1.2.14.) */
817 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
819 if (src_bitmap == dst_bitmap)
821 /* needed when blitting directly to same bitmap -- should not be needed with
822 recent SDL libraries, but apparently does not work in 1.2.11 directly */
824 static Bitmap *tmp_bitmap = NULL;
825 static int tmp_bitmap_xsize = 0;
826 static int tmp_bitmap_ysize = 0;
828 /* start with largest static bitmaps for initial bitmap size ... */
829 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
831 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
832 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
835 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
836 if (src_bitmap->width > tmp_bitmap_xsize ||
837 src_bitmap->height > tmp_bitmap_ysize)
839 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
840 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
842 FreeBitmap(tmp_bitmap);
847 if (tmp_bitmap == NULL)
848 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
851 sysCopyArea(src_bitmap, tmp_bitmap,
852 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
853 sysCopyArea(tmp_bitmap, dst_bitmap,
854 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
860 sysCopyArea(src_bitmap, dst_bitmap,
861 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
864 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
865 int src_x, int src_y, int src_width, int src_height,
866 int dst_x, int dst_y, int dst_width, int dst_height)
868 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
869 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
870 int dst_xsize = dst_width;
871 int dst_ysize = dst_height;
872 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
873 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
876 for (y = 0; y < src_ysteps; y++)
878 for (x = 0; x < src_xsteps; x++)
880 int draw_x = dst_x + x * src_xsize;
881 int draw_y = dst_y + y * src_ysize;
882 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
883 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
885 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
891 void FadeRectangle(int x, int y, int width, int height,
892 int fade_mode, int fade_delay, int post_delay,
893 void (*draw_border_function)(void))
895 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
896 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
899 SDLFadeRectangle(x, y, width, height,
900 fade_mode, fade_delay, post_delay, draw_border_function);
903 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
906 if (DrawingDeactivated(x, y, width, height))
909 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
912 sysFillRectangle(bitmap, x, y, width, height, color);
915 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
917 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
920 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
921 int width, int height)
923 if (DrawingOnBackground(x, y))
924 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
926 ClearRectangle(bitmap, x, y, width, height);
929 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
930 int src_x, int src_y, int width, int height,
931 int dst_x, int dst_y)
933 if (DrawingDeactivated(dst_x, dst_y, width, height))
936 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
937 dst_x, dst_y, BLIT_MASKED);
940 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
941 int src_x, int src_y, int width, int height,
942 int dst_x, int dst_y)
944 if (DrawingOnBackground(dst_x, dst_y))
946 /* draw background */
947 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
950 /* draw foreground */
951 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
955 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
959 void BlitTexture(Bitmap *bitmap,
960 int src_x, int src_y, int width, int height,
961 int dst_x, int dst_y)
966 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
970 void BlitTextureMasked(Bitmap *bitmap,
971 int src_x, int src_y, int width, int height,
972 int dst_x, int dst_y)
977 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
981 void BlitToScreen(Bitmap *bitmap,
982 int src_x, int src_y, int width, int height,
983 int dst_x, int dst_y)
988 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
989 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
990 width, height, dst_x, dst_y);
992 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
995 void BlitToScreenMasked(Bitmap *bitmap,
996 int src_x, int src_y, int width, int height,
997 int dst_x, int dst_y)
1002 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1003 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1004 width, height, dst_x, dst_y);
1006 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1009 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1012 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1015 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1018 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1021 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1022 int to_x, int to_y, Pixel pixel, int line_width)
1026 if (program.headless)
1029 for (x = 0; x < line_width; x++)
1031 for (y = 0; y < line_width; y++)
1033 int dx = x - line_width / 2;
1034 int dy = y - line_width / 2;
1036 if ((x == 0 && y == 0) ||
1037 (x == 0 && y == line_width - 1) ||
1038 (x == line_width - 1 && y == 0) ||
1039 (x == line_width - 1 && y == line_width - 1))
1043 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1048 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1053 for (i = 0; i < num_points - 1; i++)
1054 DrawLine(bitmap, points[i].x, points[i].y,
1055 points[i + 1].x, points[i + 1].y, pixel, line_width);
1058 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1062 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1064 if (program.headless)
1067 if (x < 0 || x >= bitmap->width ||
1068 y < 0 || y >= bitmap->height)
1071 return SDLGetPixel(bitmap, x, y);
1074 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1075 unsigned int color_g, unsigned int color_b)
1077 if (program.headless)
1080 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1083 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1085 unsigned int color_r = (color >> 16) & 0xff;
1086 unsigned int color_g = (color >> 8) & 0xff;
1087 unsigned int color_b = (color >> 0) & 0xff;
1089 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1092 void KeyboardAutoRepeatOn(void)
1094 #if defined(TARGET_SDL2)
1095 keyrepeat_status = TRUE;
1097 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1098 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1099 SDL_EnableUNICODE(1);
1103 void KeyboardAutoRepeatOff(void)
1105 #if defined(TARGET_SDL2)
1106 keyrepeat_status = FALSE;
1108 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1109 SDL_EnableUNICODE(0);
1113 boolean SetVideoMode(boolean fullscreen)
1115 return SDLSetVideoMode(fullscreen);
1118 void SetVideoFrameDelay(unsigned int frame_delay_value)
1120 video.frame_delay_value = frame_delay_value;
1123 unsigned int GetVideoFrameDelay()
1125 return video.frame_delay_value;
1128 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1130 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1131 (!fullscreen && video.fullscreen_enabled))
1132 fullscreen = SetVideoMode(fullscreen);
1137 Bitmap *LoadImage(char *filename)
1141 new_bitmap = SDLLoadImage(filename);
1144 new_bitmap->source_filename = getStringCopy(filename);
1149 Bitmap *LoadCustomImage(char *basename)
1151 char *filename = getCustomImageFilename(basename);
1154 if (filename == NULL)
1155 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1157 if ((new_bitmap = LoadImage(filename)) == NULL)
1158 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1163 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1165 char *filename = getCustomImageFilename(basename);
1168 if (filename == NULL) /* (should never happen) */
1170 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1174 if (strEqual(filename, bitmap->source_filename))
1176 /* The old and new image are the same (have the same filename and path).
1177 This usually means that this image does not exist in this graphic set
1178 and a fallback to the existing image is done. */
1183 if ((new_bitmap = LoadImage(filename)) == NULL)
1185 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1189 if (bitmap->width != new_bitmap->width ||
1190 bitmap->height != new_bitmap->height)
1192 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1194 FreeBitmap(new_bitmap);
1198 TransferBitmapPointers(new_bitmap, bitmap);
1202 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1204 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1207 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1209 if (bitmaps[IMG_BITMAP_CUSTOM])
1211 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1213 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1216 if (gfx.game_tile_size == gfx.standard_tile_size)
1218 bitmaps[IMG_BITMAP_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 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1229 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1230 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
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_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1382 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1384 boolean free_old_bitmap = TRUE;
1386 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1387 if (bitmaps[i] == old_bitmap)
1388 free_old_bitmap = FALSE;
1390 if (free_old_bitmap)
1392 /* copy image filename from old to new standard sized bitmap */
1393 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1394 getStringCopy(old_bitmap->source_filename);
1396 FreeBitmap(old_bitmap);
1401 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1404 UPDATE_BUSY_STATE();
1406 print_timestamp_done("CreateScaledBitmaps");
1409 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1412 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1415 void CreateBitmapTextures(Bitmap **bitmaps)
1417 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1420 void FreeBitmapTextures(Bitmap **bitmaps)
1422 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1425 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1427 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1431 /* ------------------------------------------------------------------------- */
1432 /* mouse pointer functions */
1433 /* ------------------------------------------------------------------------- */
1435 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1437 /* XPM image definitions */
1438 static const char *cursor_image_none[] =
1440 /* width height num_colors chars_per_pixel */
1470 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1471 static const char *cursor_image_dot[] =
1473 /* width height num_colors chars_per_pixel */
1502 static const char **cursor_image_playfield = cursor_image_dot;
1504 /* some people complained about a "white dot" on the screen and thought it
1505 was a graphical error... OK, let's just remove the whole pointer :-) */
1506 static const char **cursor_image_playfield = cursor_image_none;
1509 static const int cursor_bit_order = BIT_ORDER_MSB;
1511 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1513 struct MouseCursorInfo *cursor;
1514 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1515 int header_lines = 4;
1518 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1520 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1523 for (y = 0; y < cursor->width; y++)
1525 for (x = 0; x < cursor->height; x++)
1528 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1533 cursor->data[i] = cursor->mask[i] = 0;
1536 switch (image[header_lines + y][x])
1539 cursor->data[i] |= bit_mask;
1540 cursor->mask[i] |= bit_mask;
1544 cursor->mask[i] |= bit_mask;
1553 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1558 void SetMouseCursor(int mode)
1560 static struct MouseCursorInfo *cursor_none = NULL;
1561 static struct MouseCursorInfo *cursor_playfield = NULL;
1562 struct MouseCursorInfo *cursor_new;
1564 if (cursor_none == NULL)
1565 cursor_none = get_cursor_from_image(cursor_image_none);
1567 if (cursor_playfield == NULL)
1568 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1570 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1571 mode == CURSOR_NONE ? cursor_none :
1572 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1574 SDLSetMouseCursor(cursor_new);
1576 gfx.cursor_mode = mode;
1580 /* ========================================================================= */
1581 /* audio functions */
1582 /* ========================================================================= */
1584 void OpenAudio(void)
1586 /* always start with reliable default values */
1587 audio.sound_available = FALSE;
1588 audio.music_available = FALSE;
1589 audio.loops_available = FALSE;
1591 audio.sound_enabled = FALSE;
1592 audio.sound_deactivated = FALSE;
1594 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1595 audio.mixer_pid = 0;
1596 audio.device_name = NULL;
1597 audio.device_fd = -1;
1599 audio.num_channels = 0;
1600 audio.music_channel = 0;
1601 audio.first_sound_channel = 0;
1606 void CloseAudio(void)
1610 audio.sound_enabled = FALSE;
1613 void SetAudioMode(boolean enabled)
1615 if (!audio.sound_available)
1618 audio.sound_enabled = enabled;
1622 /* ========================================================================= */
1623 /* event functions */
1624 /* ========================================================================= */
1626 boolean PendingEvent(void)
1628 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1631 void WaitEvent(Event *event)
1633 SDLWaitEvent(event);
1636 void PeekEvent(Event *event)
1638 #if defined(TARGET_SDL2)
1639 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1641 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1645 void CheckQuitEvent(void)
1647 if (SDL_QuitRequested())
1648 program.exit_function(0);
1651 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1653 #if defined(TARGET_SDL2)
1654 /* key up/down events in SDL2 do not return text characters anymore */
1655 return event->keysym.sym;
1658 #if ENABLE_UNUSED_CODE
1659 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1660 (int)event->keysym.unicode,
1661 (int)event->keysym.sym,
1662 (int)SDL_GetModState());
1665 if (with_modifiers &&
1666 event->keysym.unicode > 0x0000 &&
1667 event->keysym.unicode < 0x2000)
1668 return event->keysym.unicode;
1670 return event->keysym.sym;
1675 KeyMod HandleKeyModState(Key key, int key_status)
1677 static KeyMod current_modifiers = KMOD_None;
1679 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1681 KeyMod new_modifier = KMOD_None;
1686 new_modifier = KMOD_Shift_L;
1689 new_modifier = KMOD_Shift_R;
1691 case KSYM_Control_L:
1692 new_modifier = KMOD_Control_L;
1694 case KSYM_Control_R:
1695 new_modifier = KMOD_Control_R;
1698 new_modifier = KMOD_Meta_L;
1701 new_modifier = KMOD_Meta_R;
1704 new_modifier = KMOD_Alt_L;
1707 new_modifier = KMOD_Alt_R;
1713 if (key_status == KEY_PRESSED)
1714 current_modifiers |= new_modifier;
1716 current_modifiers &= ~new_modifier;
1719 return current_modifiers;
1722 KeyMod GetKeyModState()
1724 return (KeyMod)SDL_GetModState();
1727 KeyMod GetKeyModStateFromEvents()
1729 /* always use key modifier state as tracked from key events (this is needed
1730 if the modifier key event was injected into the event queue, but the key
1731 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1732 query the keys as held pressed on the keyboard) -- this case is currently
1733 only used to filter out clipboard insert events from "True X-Mouse" tool */
1735 return HandleKeyModState(KSYM_UNDEFINED, 0);
1738 void StartTextInput(int x, int y, int width, int height)
1740 #if defined(TARGET_SDL2)
1741 #if defined(HAS_SCREEN_KEYBOARD)
1742 SDL_StartTextInput();
1744 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1746 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1747 video.shifted_up_delay = SDL_GetTicks();
1748 video.shifted_up = TRUE;
1754 void StopTextInput()
1756 #if defined(TARGET_SDL2)
1757 #if defined(HAS_SCREEN_KEYBOARD)
1758 SDL_StopTextInput();
1760 if (video.shifted_up)
1762 video.shifted_up_pos = 0;
1763 video.shifted_up_delay = SDL_GetTicks();
1764 video.shifted_up = FALSE;
1770 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1772 if (event->type != EVENT_CLIENTMESSAGE)
1775 return TRUE; /* the only possible message here is SDL_QUIT */
1779 /* ========================================================================= */
1780 /* joystick functions */
1781 /* ========================================================================= */
1783 void InitJoysticks()
1787 #if defined(NO_JOYSTICK)
1788 return; /* joysticks generally deactivated by compile-time directive */
1791 /* always start with reliable default values */
1792 joystick.status = JOYSTICK_NOT_AVAILABLE;
1793 for (i = 0; i < MAX_PLAYERS; i++)
1794 joystick.nr[i] = -1; /* no joystick configured */
1799 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1801 return SDLReadJoystick(nr, x, y, b1, b2);
1804 boolean CheckJoystickOpened(int nr)
1806 return SDLCheckJoystickOpened(nr);
1809 void ClearJoystickState()
1811 SDLClearJoystickState();