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 // ============================================================================
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(void)
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(void)
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(void)
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(void)
321 gfx.cursor_mode = CURSOR_DEFAULT;
324 void InitTileCursorInfo(void)
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(void)
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(void)
430 return overlay.active;
433 void SetDrawDeactivationMask(int draw_deactivation_mask)
435 gfx.draw_deactivation_mask = draw_deactivation_mask;
438 int GetDrawDeactivationMask(void)
440 return gfx.draw_deactivation_mask;
443 void SetDrawBackgroundMask(int draw_background_mask)
445 gfx.draw_background_mask = draw_background_mask;
448 static 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 // ============================================================================
496 // ============================================================================
498 static int GetRealDepth(int depth)
500 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
503 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 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 static void FreeBitmapPointers(Bitmap *bitmap)
588 SDLFreeBitmapPointers(bitmap);
590 checked_free(bitmap->source_filename);
591 bitmap->source_filename = NULL;
594 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);
663 static void CloseWindow(DrawWindow *window)
668 void SetRedrawMaskFromArea(int x, int y, int width, int height)
672 int x2 = x + width - 1;
673 int y2 = y + height - 1;
675 if (width == 0 || height == 0)
678 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
679 redraw_mask |= REDRAW_FIELD;
680 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
681 redraw_mask |= REDRAW_DOOR_1;
682 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
683 redraw_mask |= REDRAW_DOOR_2;
684 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
685 redraw_mask |= REDRAW_DOOR_3;
687 redraw_mask = REDRAW_ALL;
690 static boolean CheckDrawingArea(int x, int y, int width, int height,
693 if (draw_mask == REDRAW_NONE)
696 if (draw_mask & REDRAW_ALL)
699 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
702 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
705 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
708 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
714 boolean DrawingDeactivatedField(void)
716 if (program.headless)
719 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
725 boolean DrawingDeactivated(int x, int y, int width, int height)
727 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
730 boolean DrawingOnBackground(int x, int y)
732 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
733 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
736 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
737 int *width, int *height, boolean is_dest)
739 int clip_x, clip_y, clip_width, clip_height;
741 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
743 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
744 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
745 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
746 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
752 clip_width = bitmap->width;
753 clip_height = bitmap->height;
756 // skip if rectangle completely outside bitmap
758 if (*x + *width <= clip_x ||
759 *y + *height <= clip_y ||
760 *x >= clip_x + clip_width ||
761 *y >= clip_y + clip_height)
764 // clip if rectangle overlaps bitmap
768 *width -= clip_x - *x;
771 else if (*x + *width > clip_x + clip_width)
773 *width = clip_x + clip_width - *x;
778 *height -= clip_y - *y;
781 else if (*y + *height > clip_y + clip_height)
783 *height = clip_y + clip_height - *y;
789 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
790 int src_x, int src_y, int width, int height,
791 int dst_x, int dst_y)
793 int dst_x_unclipped = dst_x;
794 int dst_y_unclipped = dst_y;
796 if (program.headless)
799 if (src_bitmap == NULL || dst_bitmap == NULL)
802 if (DrawingDeactivated(dst_x, dst_y, width, height))
805 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
806 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
809 // source x/y might need adjustment if destination x/y was clipped top/left
810 src_x += dst_x - dst_x_unclipped;
811 src_y += dst_y - dst_y_unclipped;
813 #if defined(TARGET_SDL2)
814 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
815 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
816 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
817 but is already fixed in SVN and should therefore finally be fixed with
818 the next official SDL release, which is probably version 1.2.14.) */
819 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
821 if (src_bitmap == dst_bitmap)
823 // needed when blitting directly to same bitmap -- should not be needed with
824 // recent SDL libraries, but apparently does not work in 1.2.11 directly
826 static Bitmap *tmp_bitmap = NULL;
827 static int tmp_bitmap_xsize = 0;
828 static int tmp_bitmap_ysize = 0;
830 // start with largest static bitmaps for initial bitmap size ...
831 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
833 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
834 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
837 // ... and allow for later re-adjustments due to custom artwork bitmaps
838 if (src_bitmap->width > tmp_bitmap_xsize ||
839 src_bitmap->height > tmp_bitmap_ysize)
841 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
842 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
844 FreeBitmap(tmp_bitmap);
849 if (tmp_bitmap == NULL)
850 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
853 sysCopyArea(src_bitmap, tmp_bitmap,
854 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
855 sysCopyArea(tmp_bitmap, dst_bitmap,
856 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
862 sysCopyArea(src_bitmap, dst_bitmap,
863 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
866 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
867 int src_x, int src_y, int src_width, int src_height,
868 int dst_x, int dst_y, int dst_width, int dst_height)
870 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
871 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
872 int dst_xsize = dst_width;
873 int dst_ysize = dst_height;
874 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
875 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
878 for (y = 0; y < src_ysteps; y++)
880 for (x = 0; x < src_xsteps; x++)
882 int draw_x = dst_x + x * src_xsize;
883 int draw_y = dst_y + y * src_ysize;
884 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
885 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
887 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
893 void FadeRectangle(int x, int y, int width, int height,
894 int fade_mode, int fade_delay, int post_delay,
895 void (*draw_border_function)(void))
897 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
898 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
901 SDLFadeRectangle(x, y, width, height,
902 fade_mode, fade_delay, post_delay, draw_border_function);
905 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
908 if (DrawingDeactivated(x, y, width, height))
911 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
914 sysFillRectangle(bitmap, x, y, width, height, color);
917 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
919 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
922 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
923 int width, int height)
925 if (DrawingOnBackground(x, y))
926 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
928 ClearRectangle(bitmap, x, y, width, height);
931 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
932 int src_x, int src_y, int width, int height,
933 int dst_x, int dst_y)
935 if (DrawingDeactivated(dst_x, dst_y, width, height))
938 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
939 dst_x, dst_y, BLIT_MASKED);
942 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
943 int src_x, int src_y, int width, int height,
944 int dst_x, int dst_y)
946 if (DrawingOnBackground(dst_x, dst_y))
949 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
953 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
957 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
961 void BlitTexture(Bitmap *bitmap,
962 int src_x, int src_y, int width, int height,
963 int dst_x, int dst_y)
968 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
972 void BlitTextureMasked(Bitmap *bitmap,
973 int src_x, int src_y, int width, int height,
974 int dst_x, int dst_y)
979 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
983 void BlitToScreen(Bitmap *bitmap,
984 int src_x, int src_y, int width, int height,
985 int dst_x, int dst_y)
990 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
991 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
992 width, height, dst_x, dst_y);
994 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
997 void BlitToScreenMasked(Bitmap *bitmap,
998 int src_x, int src_y, int width, int height,
999 int dst_x, int dst_y)
1004 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1005 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1006 width, height, dst_x, dst_y);
1008 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1011 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1014 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1017 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1020 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1023 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1024 int to_x, int to_y, Pixel pixel, int line_width)
1028 if (program.headless)
1031 for (x = 0; x < line_width; x++)
1033 for (y = 0; y < line_width; y++)
1035 int dx = x - line_width / 2;
1036 int dy = y - line_width / 2;
1038 if ((x == 0 && y == 0) ||
1039 (x == 0 && y == line_width - 1) ||
1040 (x == line_width - 1 && y == 0) ||
1041 (x == line_width - 1 && y == line_width - 1))
1045 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1050 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1055 for (i = 0; i < num_points - 1; i++)
1056 DrawLine(bitmap, points[i].x, points[i].y,
1057 points[i + 1].x, points[i + 1].y, pixel, line_width);
1060 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1064 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1066 if (program.headless)
1069 if (x < 0 || x >= bitmap->width ||
1070 y < 0 || y >= bitmap->height)
1073 return SDLGetPixel(bitmap, x, y);
1076 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1077 unsigned int color_g, unsigned int color_b)
1079 if (program.headless)
1082 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1085 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1087 unsigned int color_r = (color >> 16) & 0xff;
1088 unsigned int color_g = (color >> 8) & 0xff;
1089 unsigned int color_b = (color >> 0) & 0xff;
1091 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1094 void KeyboardAutoRepeatOn(void)
1096 #if defined(TARGET_SDL2)
1097 keyrepeat_status = TRUE;
1099 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1100 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1101 SDL_EnableUNICODE(1);
1105 void KeyboardAutoRepeatOff(void)
1107 #if defined(TARGET_SDL2)
1108 keyrepeat_status = FALSE;
1110 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1111 SDL_EnableUNICODE(0);
1115 boolean SetVideoMode(boolean fullscreen)
1117 return SDLSetVideoMode(fullscreen);
1120 void SetVideoFrameDelay(unsigned int frame_delay_value)
1122 video.frame_delay_value = frame_delay_value;
1125 unsigned int GetVideoFrameDelay(void)
1127 return video.frame_delay_value;
1130 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1132 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1133 (!fullscreen && video.fullscreen_enabled))
1134 fullscreen = SetVideoMode(fullscreen);
1139 Bitmap *LoadImage(char *filename)
1143 new_bitmap = SDLLoadImage(filename);
1146 new_bitmap->source_filename = getStringCopy(filename);
1151 Bitmap *LoadCustomImage(char *basename)
1153 char *filename = getCustomImageFilename(basename);
1156 if (filename == NULL)
1157 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1159 if ((new_bitmap = LoadImage(filename)) == NULL)
1160 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1165 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1167 char *filename = getCustomImageFilename(basename);
1170 if (filename == NULL) // (should never happen)
1172 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1176 if (strEqual(filename, bitmap->source_filename))
1178 // The old and new image are the same (have the same filename and path).
1179 // This usually means that this image does not exist in this graphic set
1180 // and a fallback to the existing image is done.
1185 if ((new_bitmap = LoadImage(filename)) == NULL)
1187 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1191 if (bitmap->width != new_bitmap->width ||
1192 bitmap->height != new_bitmap->height)
1194 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1196 FreeBitmap(new_bitmap);
1200 TransferBitmapPointers(new_bitmap, bitmap);
1204 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1206 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1209 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1211 if (bitmaps[IMG_BITMAP_CUSTOM])
1213 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1215 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1218 if (gfx.game_tile_size == gfx.standard_tile_size)
1220 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1225 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1226 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1227 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1229 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1231 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1232 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1235 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1236 int tile_size, boolean create_small_bitmaps)
1238 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1239 Bitmap *tmp_bitmap_final = NULL;
1240 Bitmap *tmp_bitmap_0 = NULL;
1241 Bitmap *tmp_bitmap_1 = NULL;
1242 Bitmap *tmp_bitmap_2 = NULL;
1243 Bitmap *tmp_bitmap_4 = NULL;
1244 Bitmap *tmp_bitmap_8 = NULL;
1245 Bitmap *tmp_bitmap_16 = NULL;
1246 Bitmap *tmp_bitmap_32 = NULL;
1247 int width_final, height_final;
1248 int width_0, height_0;
1249 int width_1, height_1;
1250 int width_2, height_2;
1251 int width_4, height_4;
1252 int width_8, height_8;
1253 int width_16, height_16;
1254 int width_32, height_32;
1255 int old_width, old_height;
1258 print_timestamp_init("CreateScaledBitmaps");
1260 old_width = old_bitmap->width;
1261 old_height = old_bitmap->height;
1263 // calculate new image dimensions for final image size
1264 width_final = old_width * zoom_factor;
1265 height_final = old_height * zoom_factor;
1267 // get image with final size (this might require scaling up)
1268 // ("final" size may result in non-standard tile size image)
1269 if (zoom_factor != 1)
1270 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1272 tmp_bitmap_final = old_bitmap;
1274 UPDATE_BUSY_STATE();
1276 width_0 = width_1 = width_final;
1277 height_0 = height_1 = height_final;
1279 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1281 if (create_small_bitmaps)
1283 // check if we have a non-gameplay tile size image
1284 if (tile_size != gfx.game_tile_size)
1286 // get image with gameplay tile size
1287 width_0 = width_final * gfx.game_tile_size / tile_size;
1288 height_0 = height_final * gfx.game_tile_size / tile_size;
1290 if (width_0 == old_width)
1291 tmp_bitmap_0 = old_bitmap;
1292 else if (width_0 == width_final)
1293 tmp_bitmap_0 = tmp_bitmap_final;
1295 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1297 UPDATE_BUSY_STATE();
1300 // check if we have a non-standard tile size image
1301 if (tile_size != gfx.standard_tile_size)
1303 // get image with standard tile size
1304 width_1 = width_final * gfx.standard_tile_size / tile_size;
1305 height_1 = height_final * gfx.standard_tile_size / tile_size;
1307 if (width_1 == old_width)
1308 tmp_bitmap_1 = old_bitmap;
1309 else if (width_1 == width_final)
1310 tmp_bitmap_1 = tmp_bitmap_final;
1311 else if (width_1 == width_0)
1312 tmp_bitmap_1 = tmp_bitmap_0;
1314 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1316 UPDATE_BUSY_STATE();
1319 // calculate new image dimensions for small images
1320 width_2 = width_1 / 2;
1321 height_2 = height_1 / 2;
1322 width_4 = width_1 / 4;
1323 height_4 = height_1 / 4;
1324 width_8 = width_1 / 8;
1325 height_8 = height_1 / 8;
1326 width_16 = width_1 / 16;
1327 height_16 = height_1 / 16;
1328 width_32 = width_1 / 32;
1329 height_32 = height_1 / 32;
1331 // get image with 1/2 of normal size (for use in the level editor)
1332 if (width_2 == old_width)
1333 tmp_bitmap_2 = old_bitmap;
1335 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1337 UPDATE_BUSY_STATE();
1339 // get image with 1/4 of normal size (for use in the level editor)
1340 if (width_4 == old_width)
1341 tmp_bitmap_4 = old_bitmap;
1343 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1345 UPDATE_BUSY_STATE();
1347 // get image with 1/8 of normal size (for use on the preview screen)
1348 if (width_8 == old_width)
1349 tmp_bitmap_8 = old_bitmap;
1351 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1353 UPDATE_BUSY_STATE();
1355 // get image with 1/16 of normal size (for use on the preview screen)
1356 if (width_16 == old_width)
1357 tmp_bitmap_16 = old_bitmap;
1359 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1361 UPDATE_BUSY_STATE();
1363 // get image with 1/32 of normal size (for use on the preview screen)
1364 if (width_32 == old_width)
1365 tmp_bitmap_32 = old_bitmap;
1367 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1369 UPDATE_BUSY_STATE();
1371 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1372 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1373 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1374 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1375 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1376 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1378 if (width_0 != width_1)
1379 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1381 if (bitmaps[IMG_BITMAP_CUSTOM])
1382 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1384 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1386 boolean free_old_bitmap = TRUE;
1388 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1389 if (bitmaps[i] == old_bitmap)
1390 free_old_bitmap = FALSE;
1392 if (free_old_bitmap)
1394 // copy image filename from old to new standard sized bitmap
1395 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1396 getStringCopy(old_bitmap->source_filename);
1398 FreeBitmap(old_bitmap);
1403 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1406 UPDATE_BUSY_STATE();
1408 print_timestamp_done("CreateScaledBitmaps");
1411 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1414 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1417 void CreateBitmapTextures(Bitmap **bitmaps)
1419 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1422 void FreeBitmapTextures(Bitmap **bitmaps)
1424 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1427 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1429 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1433 // ----------------------------------------------------------------------------
1434 // mouse pointer functions
1435 // ----------------------------------------------------------------------------
1437 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1439 // XPM image definitions
1440 static const char *cursor_image_none[] =
1442 // width height num_colors chars_per_pixel
1472 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1473 static const char *cursor_image_dot[] =
1475 // width height num_colors chars_per_pixel
1504 static const char **cursor_image_playfield = cursor_image_dot;
1506 // some people complained about a "white dot" on the screen and thought it
1507 // was a graphical error... OK, let's just remove the whole pointer :-)
1508 static const char **cursor_image_playfield = cursor_image_none;
1511 static const int cursor_bit_order = BIT_ORDER_MSB;
1513 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1515 struct MouseCursorInfo *cursor;
1516 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1517 int header_lines = 4;
1520 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1522 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1525 for (y = 0; y < cursor->width; y++)
1527 for (x = 0; x < cursor->height; x++)
1530 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1535 cursor->data[i] = cursor->mask[i] = 0;
1538 switch (image[header_lines + y][x])
1541 cursor->data[i] |= bit_mask;
1542 cursor->mask[i] |= bit_mask;
1546 cursor->mask[i] |= bit_mask;
1555 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1560 void SetMouseCursor(int mode)
1562 static struct MouseCursorInfo *cursor_none = NULL;
1563 static struct MouseCursorInfo *cursor_playfield = NULL;
1564 struct MouseCursorInfo *cursor_new;
1566 if (cursor_none == NULL)
1567 cursor_none = get_cursor_from_image(cursor_image_none);
1569 if (cursor_playfield == NULL)
1570 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1572 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1573 mode == CURSOR_NONE ? cursor_none :
1574 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1576 SDLSetMouseCursor(cursor_new);
1578 gfx.cursor_mode = mode;
1582 // ============================================================================
1584 // ============================================================================
1586 void OpenAudio(void)
1588 // always start with reliable default values
1589 audio.sound_available = FALSE;
1590 audio.music_available = FALSE;
1591 audio.loops_available = FALSE;
1593 audio.sound_enabled = FALSE;
1594 audio.sound_deactivated = FALSE;
1596 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1597 audio.mixer_pid = 0;
1598 audio.device_name = NULL;
1599 audio.device_fd = -1;
1601 audio.num_channels = 0;
1602 audio.music_channel = 0;
1603 audio.first_sound_channel = 0;
1608 void CloseAudio(void)
1612 audio.sound_enabled = FALSE;
1615 void SetAudioMode(boolean enabled)
1617 if (!audio.sound_available)
1620 audio.sound_enabled = enabled;
1624 // ============================================================================
1626 // ============================================================================
1628 boolean PendingEvent(void)
1630 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1633 void WaitEvent(Event *event)
1635 SDLWaitEvent(event);
1638 void PeekEvent(Event *event)
1640 #if defined(TARGET_SDL2)
1641 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1643 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1647 void CheckQuitEvent(void)
1649 if (SDL_QuitRequested())
1650 program.exit_function(0);
1653 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1655 #if defined(TARGET_SDL2)
1656 // key up/down events in SDL2 do not return text characters anymore
1657 return event->keysym.sym;
1660 #if ENABLE_UNUSED_CODE
1661 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1662 (int)event->keysym.unicode,
1663 (int)event->keysym.sym,
1664 (int)SDL_GetModState());
1667 if (with_modifiers &&
1668 event->keysym.unicode > 0x0000 &&
1669 event->keysym.unicode < 0x2000)
1670 return event->keysym.unicode;
1672 return event->keysym.sym;
1677 KeyMod HandleKeyModState(Key key, int key_status)
1679 static KeyMod current_modifiers = KMOD_None;
1681 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1683 KeyMod new_modifier = KMOD_None;
1688 new_modifier = KMOD_Shift_L;
1691 new_modifier = KMOD_Shift_R;
1693 case KSYM_Control_L:
1694 new_modifier = KMOD_Control_L;
1696 case KSYM_Control_R:
1697 new_modifier = KMOD_Control_R;
1700 new_modifier = KMOD_Meta_L;
1703 new_modifier = KMOD_Meta_R;
1706 new_modifier = KMOD_Alt_L;
1709 new_modifier = KMOD_Alt_R;
1715 if (key_status == KEY_PRESSED)
1716 current_modifiers |= new_modifier;
1718 current_modifiers &= ~new_modifier;
1721 return current_modifiers;
1724 KeyMod GetKeyModState(void)
1726 return (KeyMod)SDL_GetModState();
1729 KeyMod GetKeyModStateFromEvents(void)
1731 /* always use key modifier state as tracked from key events (this is needed
1732 if the modifier key event was injected into the event queue, but the key
1733 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1734 query the keys as held pressed on the keyboard) -- this case is currently
1735 only used to filter out clipboard insert events from "True X-Mouse" tool */
1737 return HandleKeyModState(KSYM_UNDEFINED, 0);
1740 void StartTextInput(int x, int y, int width, int height)
1742 #if defined(TARGET_SDL2)
1743 #if defined(HAS_SCREEN_KEYBOARD)
1744 SDL_StartTextInput();
1746 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1748 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1749 video.shifted_up_delay = SDL_GetTicks();
1750 video.shifted_up = TRUE;
1756 void StopTextInput(void)
1758 #if defined(TARGET_SDL2)
1759 #if defined(HAS_SCREEN_KEYBOARD)
1760 SDL_StopTextInput();
1762 if (video.shifted_up)
1764 video.shifted_up_pos = 0;
1765 video.shifted_up_delay = SDL_GetTicks();
1766 video.shifted_up = FALSE;
1772 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1774 if (event->type != EVENT_CLIENTMESSAGE)
1777 return TRUE; // the only possible message here is SDL_QUIT
1781 // ============================================================================
1782 // joystick functions
1783 // ============================================================================
1785 void InitJoysticks(void)
1789 #if defined(NO_JOYSTICK)
1790 return; // joysticks generally deactivated by compile-time directive
1793 // always start with reliable default values
1794 joystick.status = JOYSTICK_NOT_AVAILABLE;
1795 for (i = 0; i < MAX_PLAYERS; i++)
1796 joystick.nr[i] = -1; // no joystick configured
1801 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1803 return SDLReadJoystick(nr, x, y, b1, b2);
1806 boolean CheckJoystickOpened(int nr)
1808 return SDLCheckJoystickOpened(nr);
1811 void ClearJoystickState(void)
1813 SDLClearJoystickState();