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)
1391 FreeBitmap(old_bitmap);
1395 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1398 UPDATE_BUSY_STATE();
1400 print_timestamp_done("CreateScaledBitmaps");
1403 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1406 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1409 void CreateBitmapTextures(Bitmap **bitmaps)
1411 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1414 void FreeBitmapTextures(Bitmap **bitmaps)
1416 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1419 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1421 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1425 /* ------------------------------------------------------------------------- */
1426 /* mouse pointer functions */
1427 /* ------------------------------------------------------------------------- */
1429 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1431 /* XPM image definitions */
1432 static const char *cursor_image_none[] =
1434 /* width height num_colors chars_per_pixel */
1464 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1465 static const char *cursor_image_dot[] =
1467 /* width height num_colors chars_per_pixel */
1496 static const char **cursor_image_playfield = cursor_image_dot;
1498 /* some people complained about a "white dot" on the screen and thought it
1499 was a graphical error... OK, let's just remove the whole pointer :-) */
1500 static const char **cursor_image_playfield = cursor_image_none;
1503 static const int cursor_bit_order = BIT_ORDER_MSB;
1505 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1507 struct MouseCursorInfo *cursor;
1508 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1509 int header_lines = 4;
1512 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1514 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1517 for (y = 0; y < cursor->width; y++)
1519 for (x = 0; x < cursor->height; x++)
1522 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1527 cursor->data[i] = cursor->mask[i] = 0;
1530 switch (image[header_lines + y][x])
1533 cursor->data[i] |= bit_mask;
1534 cursor->mask[i] |= bit_mask;
1538 cursor->mask[i] |= bit_mask;
1547 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1552 void SetMouseCursor(int mode)
1554 static struct MouseCursorInfo *cursor_none = NULL;
1555 static struct MouseCursorInfo *cursor_playfield = NULL;
1556 struct MouseCursorInfo *cursor_new;
1558 if (cursor_none == NULL)
1559 cursor_none = get_cursor_from_image(cursor_image_none);
1561 if (cursor_playfield == NULL)
1562 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1564 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1565 mode == CURSOR_NONE ? cursor_none :
1566 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1568 SDLSetMouseCursor(cursor_new);
1570 gfx.cursor_mode = mode;
1574 /* ========================================================================= */
1575 /* audio functions */
1576 /* ========================================================================= */
1578 void OpenAudio(void)
1580 /* always start with reliable default values */
1581 audio.sound_available = FALSE;
1582 audio.music_available = FALSE;
1583 audio.loops_available = FALSE;
1585 audio.sound_enabled = FALSE;
1586 audio.sound_deactivated = FALSE;
1588 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1589 audio.mixer_pid = 0;
1590 audio.device_name = NULL;
1591 audio.device_fd = -1;
1593 audio.num_channels = 0;
1594 audio.music_channel = 0;
1595 audio.first_sound_channel = 0;
1600 void CloseAudio(void)
1604 audio.sound_enabled = FALSE;
1607 void SetAudioMode(boolean enabled)
1609 if (!audio.sound_available)
1612 audio.sound_enabled = enabled;
1616 /* ========================================================================= */
1617 /* event functions */
1618 /* ========================================================================= */
1620 boolean PendingEvent(void)
1622 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1625 void WaitEvent(Event *event)
1627 SDLWaitEvent(event);
1630 void PeekEvent(Event *event)
1632 #if defined(TARGET_SDL2)
1633 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1635 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1639 void CheckQuitEvent(void)
1641 if (SDL_QuitRequested())
1642 program.exit_function(0);
1645 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1647 #if defined(TARGET_SDL2)
1648 /* key up/down events in SDL2 do not return text characters anymore */
1649 return event->keysym.sym;
1652 #if ENABLE_UNUSED_CODE
1653 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1654 (int)event->keysym.unicode,
1655 (int)event->keysym.sym,
1656 (int)SDL_GetModState());
1659 if (with_modifiers &&
1660 event->keysym.unicode > 0x0000 &&
1661 event->keysym.unicode < 0x2000)
1662 return event->keysym.unicode;
1664 return event->keysym.sym;
1669 KeyMod HandleKeyModState(Key key, int key_status)
1671 static KeyMod current_modifiers = KMOD_None;
1673 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1675 KeyMod new_modifier = KMOD_None;
1680 new_modifier = KMOD_Shift_L;
1683 new_modifier = KMOD_Shift_R;
1685 case KSYM_Control_L:
1686 new_modifier = KMOD_Control_L;
1688 case KSYM_Control_R:
1689 new_modifier = KMOD_Control_R;
1692 new_modifier = KMOD_Meta_L;
1695 new_modifier = KMOD_Meta_R;
1698 new_modifier = KMOD_Alt_L;
1701 new_modifier = KMOD_Alt_R;
1707 if (key_status == KEY_PRESSED)
1708 current_modifiers |= new_modifier;
1710 current_modifiers &= ~new_modifier;
1713 return current_modifiers;
1716 KeyMod GetKeyModState()
1718 return (KeyMod)SDL_GetModState();
1721 KeyMod GetKeyModStateFromEvents()
1723 /* always use key modifier state as tracked from key events (this is needed
1724 if the modifier key event was injected into the event queue, but the key
1725 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1726 query the keys as held pressed on the keyboard) -- this case is currently
1727 only used to filter out clipboard insert events from "True X-Mouse" tool */
1729 return HandleKeyModState(KSYM_UNDEFINED, 0);
1732 void StartTextInput(int x, int y, int width, int height)
1734 #if defined(TARGET_SDL2)
1735 #if defined(HAS_SCREEN_KEYBOARD)
1736 SDL_StartTextInput();
1738 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1740 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1741 video.shifted_up_delay = SDL_GetTicks();
1742 video.shifted_up = TRUE;
1748 void StopTextInput()
1750 #if defined(TARGET_SDL2)
1751 #if defined(HAS_SCREEN_KEYBOARD)
1752 SDL_StopTextInput();
1754 if (video.shifted_up)
1756 video.shifted_up_pos = 0;
1757 video.shifted_up_delay = SDL_GetTicks();
1758 video.shifted_up = FALSE;
1764 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1766 if (event->type != EVENT_CLIENTMESSAGE)
1769 return TRUE; /* the only possible message here is SDL_QUIT */
1773 /* ========================================================================= */
1774 /* joystick functions */
1775 /* ========================================================================= */
1777 void InitJoysticks()
1781 #if defined(NO_JOYSTICK)
1782 return; /* joysticks generally deactivated by compile-time directive */
1785 /* always start with reliable default values */
1786 joystick.status = JOYSTICK_NOT_AVAILABLE;
1787 for (i = 0; i < MAX_PLAYERS; i++)
1788 joystick.nr[i] = -1; /* no joystick configured */
1793 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1795 return SDLReadJoystick(nr, x, y, b1, b2);
1798 boolean CheckJoystickOpened(int nr)
1800 return SDLCheckJoystickOpened(nr);
1803 void ClearJoystickState()
1805 SDLClearJoystickState();