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 LevelStats level_stats[MAX_LEVELS];
50 DrawWindow *window = NULL;
51 DrawBuffer *backbuffer = NULL;
52 DrawBuffer *drawto = NULL;
54 int button_status = MB_NOT_PRESSED;
55 boolean motion_status = FALSE;
56 int wheel_steps = DEFAULT_WHEEL_STEPS;
57 #if defined(TARGET_SDL2)
58 boolean keyrepeat_status = TRUE;
61 int redraw_mask = REDRAW_NONE;
66 /* ========================================================================= */
67 /* init/close functions */
68 /* ========================================================================= */
70 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
71 char *program_title, char *icon_title,
72 char *icon_filename, char *cookie_prefix,
73 char *program_version_string, int program_version)
75 program.command_basepath = getBasePath(argv0);
76 program.command_basename = getBaseName(argv0);
78 program.config_filename = config_filename;
80 program.userdata_subdir = userdata_subdir;
81 program.userdata_path = getUserGameDataDir();
83 program.program_title = program_title;
84 program.window_title = "(undefined)";
85 program.icon_title = icon_title;
87 program.icon_filename = icon_filename;
89 program.cookie_prefix = cookie_prefix;
91 program.version_super = VERSION_SUPER(program_version);
92 program.version_major = VERSION_MAJOR(program_version);
93 program.version_minor = VERSION_MINOR(program_version);
94 program.version_patch = VERSION_PATCH(program_version);
95 program.version_ident = program_version;
97 program.version_string = program_version_string;
99 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
100 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
101 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
102 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
104 program.headless = FALSE;
107 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
108 char *server_host, int server_port)
110 network.enabled = enabled;
111 network.connected = connected;
112 network.serveronly = serveronly;
114 network.server_host = server_host;
115 network.server_port = server_port;
118 void InitScoresInfo()
120 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
122 program.global_scores = directoryExists(global_scores_dir);
123 program.many_scores_per_name = !program.global_scores;
128 if (program.global_scores)
130 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
132 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
133 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
137 Error(ERR_DEBUG, "Using private, single-user scores directory.");
142 free(global_scores_dir);
145 void SetWindowTitle()
147 program.window_title = program.window_title_function();
152 void InitWindowTitleFunction(char *(*window_title_function)(void))
154 program.window_title_function = window_title_function;
157 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
159 program.exit_message_function = exit_message_function;
162 void InitExitFunction(void (*exit_function)(int))
164 program.exit_function = exit_function;
166 /* set signal handlers to custom exit function */
167 // signal(SIGINT, exit_function);
168 signal(SIGTERM, exit_function);
170 /* set exit function to automatically cleanup SDL stuff after exit() */
174 void InitPlatformDependentStuff(void)
176 // this is initialized in GetOptions(), but may already be used before
177 options.verbose = TRUE;
181 #if defined(TARGET_SDL2)
182 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
184 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
187 if (SDL_Init(sdl_init_flags) < 0)
188 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
193 void ClosePlatformDependentStuff(void)
198 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
199 int real_sx, int real_sy,
200 int full_sxsize, int full_sysize,
201 Bitmap *field_save_buffer)
207 gfx.real_sx = real_sx;
208 gfx.real_sy = real_sy;
209 gfx.full_sxsize = full_sxsize;
210 gfx.full_sysize = full_sysize;
212 gfx.field_save_buffer = field_save_buffer;
214 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
215 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
218 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
220 gfx.game_tile_size = game_tile_size;
221 gfx.standard_tile_size = standard_tile_size;
224 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
232 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
240 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
248 void InitGfxWindowInfo(int win_xsize, int win_ysize)
250 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
252 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
254 #if defined(TARGET_SDL2)
255 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
258 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
259 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
260 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
261 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
263 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
266 gfx.win_xsize = win_xsize;
267 gfx.win_ysize = win_ysize;
269 gfx.background_bitmap_mask = REDRAW_NONE;
272 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
274 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
275 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
276 gfx.scrollbuffer_width = scrollbuffer_width;
277 gfx.scrollbuffer_height = scrollbuffer_height;
280 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
282 gfx.clipping_enabled = enabled;
285 gfx.clip_width = width;
286 gfx.clip_height = height;
289 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
291 gfx.draw_busy_anim_function = draw_busy_anim_function;
294 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
296 gfx.draw_global_anim_function = draw_global_anim_function;
299 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
301 gfx.draw_global_border_function = draw_global_border_function;
304 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
306 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
309 void InitGfxCustomArtworkInfo()
311 gfx.override_level_graphics = FALSE;
312 gfx.override_level_sounds = FALSE;
313 gfx.override_level_music = FALSE;
315 gfx.draw_init_text = TRUE;
318 void InitGfxOtherSettings()
320 gfx.cursor_mode = CURSOR_DEFAULT;
323 void InitTileCursorInfo()
325 tile_cursor.enabled = FALSE;
326 tile_cursor.active = FALSE;
327 tile_cursor.moving = FALSE;
329 tile_cursor.xpos = 0;
330 tile_cursor.ypos = 0;
333 tile_cursor.target_x = 0;
334 tile_cursor.target_y = 0;
340 void InitOverlayInfo()
342 int nr = GRID_ACTIVE_NR();
345 overlay.enabled = FALSE;
346 overlay.active = FALSE;
348 overlay.show_grid = FALSE;
350 overlay.grid_xsize = setup.touch.grid_xsize[nr];
351 overlay.grid_ysize = setup.touch.grid_ysize[nr];
353 for (x = 0; x < MAX_GRID_XSIZE; x++)
354 for (y = 0; y < MAX_GRID_YSIZE; y++)
355 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
357 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
358 overlay.grid_button_action = JOY_NO_ACTION;
360 #if defined(USE_TOUCH_INPUT_OVERLAY)
361 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
362 overlay.enabled = TRUE;
366 void SetTileCursorEnabled(boolean enabled)
368 tile_cursor.enabled = enabled;
371 void SetTileCursorActive(boolean active)
373 tile_cursor.active = active;
376 void SetTileCursorTargetXY(int x, int y)
378 // delayed placement of tile selection cursor at target position
379 // (tile cursor will be moved to target position step by step)
381 tile_cursor.xpos = x;
382 tile_cursor.ypos = y;
383 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
384 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
386 tile_cursor.moving = TRUE;
389 void SetTileCursorXY(int x, int y)
391 // immediate placement of tile selection cursor at target position
393 SetTileCursorTargetXY(x, y);
395 tile_cursor.x = tile_cursor.target_x;
396 tile_cursor.y = tile_cursor.target_y;
398 tile_cursor.moving = FALSE;
401 void SetTileCursorSXSY(int sx, int sy)
407 void SetOverlayEnabled(boolean enabled)
409 overlay.enabled = enabled;
412 void SetOverlayActive(boolean active)
414 overlay.active = active;
417 void SetOverlayShowGrid(boolean show_grid)
419 overlay.show_grid = show_grid;
421 SetOverlayActive(show_grid);
424 SetOverlayEnabled(TRUE);
427 boolean GetOverlayActive()
429 return overlay.active;
432 void SetDrawDeactivationMask(int draw_deactivation_mask)
434 gfx.draw_deactivation_mask = draw_deactivation_mask;
437 int GetDrawDeactivationMask()
439 return gfx.draw_deactivation_mask;
442 void SetDrawBackgroundMask(int draw_background_mask)
444 gfx.draw_background_mask = draw_background_mask;
447 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
449 if (background_bitmap_tile != NULL)
450 gfx.background_bitmap_mask |= mask;
452 gfx.background_bitmap_mask &= ~mask;
454 if (background_bitmap_tile == NULL) /* empty background requested */
457 if (mask == REDRAW_ALL)
458 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
459 0, 0, video.width, video.height);
460 else if (mask == REDRAW_FIELD)
461 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
462 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
463 else if (mask == REDRAW_DOOR_1)
464 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
465 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
468 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
470 /* remove every mask before setting mask for window */
471 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
472 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
473 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
476 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
478 /* remove window area mask before setting mask for main area */
479 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
480 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
481 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
484 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
486 /* remove window area mask before setting mask for door area */
487 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
488 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
489 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
493 /* ========================================================================= */
494 /* video functions */
495 /* ========================================================================= */
497 inline static int GetRealDepth(int depth)
499 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
502 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
503 int width, int height, Pixel color)
505 SDLFillRectangle(bitmap, x, y, width, height, color);
507 if (bitmap == backbuffer)
508 SetRedrawMaskFromArea(x, y, width, height);
511 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
512 int src_x, int src_y, int width, int height,
513 int dst_x, int dst_y, int mask_mode)
515 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
516 dst_x, dst_y, mask_mode);
518 if (dst_bitmap == backbuffer)
519 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
522 void LimitScreenUpdates(boolean enable)
524 SDLLimitScreenUpdates(enable);
527 void InitVideoDefaults(void)
529 video.default_depth = 32;
532 void InitVideoDisplay(void)
534 if (program.headless)
537 SDLInitVideoDisplay();
538 #if defined(TARGET_SDL2)
543 void CloseVideoDisplay(void)
545 KeyboardAutoRepeatOn();
547 SDL_QuitSubSystem(SDL_INIT_VIDEO);
550 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
553 video.height = height;
554 video.depth = GetRealDepth(depth);
556 video.screen_width = width;
557 video.screen_height = height;
558 video.screen_xoffset = 0;
559 video.screen_yoffset = 0;
561 video.fullscreen_available = FULLSCREEN_STATUS;
562 video.fullscreen_enabled = FALSE;
564 video.window_scaling_available = WINDOW_SCALING_STATUS;
566 video.frame_delay = 0;
567 video.frame_delay_value = GAME_FRAME_DELAY;
569 video.shifted_up = FALSE;
570 video.shifted_up_pos = 0;
571 video.shifted_up_pos_last = 0;
572 video.shifted_up_delay = 0;
573 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
575 SDLInitVideoBuffer(fullscreen);
577 video.initialized = !program.headless;
582 inline static void FreeBitmapPointers(Bitmap *bitmap)
587 SDLFreeBitmapPointers(bitmap);
589 checked_free(bitmap->source_filename);
590 bitmap->source_filename = NULL;
593 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
596 if (src_bitmap == NULL || dst_bitmap == NULL)
599 FreeBitmapPointers(dst_bitmap);
601 *dst_bitmap = *src_bitmap;
604 void FreeBitmap(Bitmap *bitmap)
609 FreeBitmapPointers(bitmap);
614 Bitmap *CreateBitmapStruct(void)
616 return checked_calloc(sizeof(Bitmap));
619 Bitmap *CreateBitmap(int width, int height, int depth)
621 Bitmap *new_bitmap = CreateBitmapStruct();
622 int real_width = MAX(1, width); /* prevent zero bitmap width */
623 int real_height = MAX(1, height); /* prevent zero bitmap height */
624 int real_depth = GetRealDepth(depth);
626 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
628 new_bitmap->width = real_width;
629 new_bitmap->height = real_height;
634 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
638 /* if new bitmap size fits into old one, no need to re-create it */
639 if (width <= (*bitmap)->width &&
640 height <= (*bitmap)->height)
643 /* else adjust size so that old and new bitmap size fit into it */
644 width = MAX(width, (*bitmap)->width);
645 height = MAX(height, (*bitmap)->height);
648 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
652 *bitmap = new_bitmap;
656 TransferBitmapPointers(new_bitmap, *bitmap);
661 void CloseWindow(DrawWindow *window)
665 void SetRedrawMaskFromArea(int x, int y, int width, int height)
669 int x2 = x + width - 1;
670 int y2 = y + height - 1;
672 if (width == 0 || height == 0)
675 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
676 redraw_mask |= REDRAW_FIELD;
677 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
678 redraw_mask |= REDRAW_DOOR_1;
679 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
680 redraw_mask |= REDRAW_DOOR_2;
681 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
682 redraw_mask |= REDRAW_DOOR_3;
684 redraw_mask = REDRAW_ALL;
687 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
690 if (draw_mask == REDRAW_NONE)
693 if (draw_mask & REDRAW_ALL)
696 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
699 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
702 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
705 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
711 boolean DrawingDeactivatedField()
713 if (program.headless)
716 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
722 boolean DrawingDeactivated(int x, int y, int width, int height)
724 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
727 boolean DrawingOnBackground(int x, int y)
729 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
730 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
733 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
734 int *width, int *height, boolean is_dest)
736 int clip_x, clip_y, clip_width, clip_height;
738 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
740 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
741 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
742 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
743 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
749 clip_width = bitmap->width;
750 clip_height = bitmap->height;
753 /* skip if rectangle completely outside bitmap */
755 if (*x + *width <= clip_x ||
756 *y + *height <= clip_y ||
757 *x >= clip_x + clip_width ||
758 *y >= clip_y + clip_height)
761 /* clip if rectangle overlaps bitmap */
765 *width -= clip_x - *x;
768 else if (*x + *width > clip_x + clip_width)
770 *width = clip_x + clip_width - *x;
775 *height -= clip_y - *y;
778 else if (*y + *height > clip_y + clip_height)
780 *height = clip_y + clip_height - *y;
786 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
787 int src_x, int src_y, int width, int height,
788 int dst_x, int dst_y)
790 int dst_x_unclipped = dst_x;
791 int dst_y_unclipped = dst_y;
793 if (program.headless)
796 if (src_bitmap == NULL || dst_bitmap == NULL)
799 if (DrawingDeactivated(dst_x, dst_y, width, height))
802 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
803 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
806 /* source x/y might need adjustment if destination x/y was clipped top/left */
807 src_x += dst_x - dst_x_unclipped;
808 src_y += dst_y - dst_y_unclipped;
810 #if defined(TARGET_SDL2)
811 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
812 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
813 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
814 but is already fixed in SVN and should therefore finally be fixed with
815 the next official SDL release, which is probably version 1.2.14.) */
816 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
818 if (src_bitmap == dst_bitmap)
820 /* needed when blitting directly to same bitmap -- should not be needed with
821 recent SDL libraries, but apparently does not work in 1.2.11 directly */
823 static Bitmap *tmp_bitmap = NULL;
824 static int tmp_bitmap_xsize = 0;
825 static int tmp_bitmap_ysize = 0;
827 /* start with largest static bitmaps for initial bitmap size ... */
828 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
830 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
831 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
834 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
835 if (src_bitmap->width > tmp_bitmap_xsize ||
836 src_bitmap->height > tmp_bitmap_ysize)
838 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
839 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
841 FreeBitmap(tmp_bitmap);
846 if (tmp_bitmap == NULL)
847 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
850 sysCopyArea(src_bitmap, tmp_bitmap,
851 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
852 sysCopyArea(tmp_bitmap, dst_bitmap,
853 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
859 sysCopyArea(src_bitmap, dst_bitmap,
860 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
863 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
864 int src_x, int src_y, int src_width, int src_height,
865 int dst_x, int dst_y, int dst_width, int dst_height)
867 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
868 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
869 int dst_xsize = dst_width;
870 int dst_ysize = dst_height;
871 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
872 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
875 for (y = 0; y < src_ysteps; y++)
877 for (x = 0; x < src_xsteps; x++)
879 int draw_x = dst_x + x * src_xsize;
880 int draw_y = dst_y + y * src_ysize;
881 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
882 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
884 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
890 void FadeRectangle(int x, int y, int width, int height,
891 int fade_mode, int fade_delay, int post_delay,
892 void (*draw_border_function)(void))
894 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
895 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
898 SDLFadeRectangle(x, y, width, height,
899 fade_mode, fade_delay, post_delay, draw_border_function);
902 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
905 if (DrawingDeactivated(x, y, width, height))
908 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
911 sysFillRectangle(bitmap, x, y, width, height, color);
914 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
916 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
919 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
920 int width, int height)
922 if (DrawingOnBackground(x, y))
923 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
925 ClearRectangle(bitmap, x, y, width, height);
928 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
929 int src_x, int src_y, int width, int height,
930 int dst_x, int dst_y)
932 if (DrawingDeactivated(dst_x, dst_y, width, height))
935 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
936 dst_x, dst_y, BLIT_MASKED);
939 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
940 int src_x, int src_y, int width, int height,
941 int dst_x, int dst_y)
943 if (DrawingOnBackground(dst_x, dst_y))
945 /* draw background */
946 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
949 /* draw foreground */
950 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
954 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
958 void BlitTexture(Bitmap *bitmap,
959 int src_x, int src_y, int width, int height,
960 int dst_x, int dst_y)
965 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
969 void BlitTextureMasked(Bitmap *bitmap,
970 int src_x, int src_y, int width, int height,
971 int dst_x, int dst_y)
976 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
980 void BlitToScreen(Bitmap *bitmap,
981 int src_x, int src_y, int width, int height,
982 int dst_x, int dst_y)
987 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
988 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
989 width, height, dst_x, dst_y);
991 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
994 void BlitToScreenMasked(Bitmap *bitmap,
995 int src_x, int src_y, int width, int height,
996 int dst_x, int dst_y)
1001 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1002 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1003 width, height, dst_x, dst_y);
1005 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1008 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1011 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1014 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1017 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1020 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1021 int to_x, int to_y, Pixel pixel, int line_width)
1025 if (program.headless)
1028 for (x = 0; x < line_width; x++)
1030 for (y = 0; y < line_width; y++)
1032 int dx = x - line_width / 2;
1033 int dy = y - line_width / 2;
1035 if ((x == 0 && y == 0) ||
1036 (x == 0 && y == line_width - 1) ||
1037 (x == line_width - 1 && y == 0) ||
1038 (x == line_width - 1 && y == line_width - 1))
1042 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1047 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1052 for (i = 0; i < num_points - 1; i++)
1053 DrawLine(bitmap, points[i].x, points[i].y,
1054 points[i + 1].x, points[i + 1].y, pixel, line_width);
1057 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1061 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1063 if (program.headless)
1066 if (x < 0 || x >= bitmap->width ||
1067 y < 0 || y >= bitmap->height)
1070 return SDLGetPixel(bitmap, x, y);
1073 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1074 unsigned int color_g, unsigned int color_b)
1076 if (program.headless)
1079 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1082 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1084 unsigned int color_r = (color >> 16) & 0xff;
1085 unsigned int color_g = (color >> 8) & 0xff;
1086 unsigned int color_b = (color >> 0) & 0xff;
1088 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1091 void KeyboardAutoRepeatOn(void)
1093 #if defined(TARGET_SDL2)
1094 keyrepeat_status = TRUE;
1096 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1097 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1098 SDL_EnableUNICODE(1);
1102 void KeyboardAutoRepeatOff(void)
1104 #if defined(TARGET_SDL2)
1105 keyrepeat_status = FALSE;
1107 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1108 SDL_EnableUNICODE(0);
1112 boolean SetVideoMode(boolean fullscreen)
1114 return SDLSetVideoMode(fullscreen);
1117 void SetVideoFrameDelay(unsigned int frame_delay_value)
1119 video.frame_delay_value = frame_delay_value;
1122 unsigned int GetVideoFrameDelay()
1124 return video.frame_delay_value;
1127 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1129 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1130 (!fullscreen && video.fullscreen_enabled))
1131 fullscreen = SetVideoMode(fullscreen);
1136 Bitmap *LoadImage(char *filename)
1140 new_bitmap = SDLLoadImage(filename);
1143 new_bitmap->source_filename = getStringCopy(filename);
1148 Bitmap *LoadCustomImage(char *basename)
1150 char *filename = getCustomImageFilename(basename);
1153 if (filename == NULL)
1154 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1156 if ((new_bitmap = LoadImage(filename)) == NULL)
1157 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1162 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1164 char *filename = getCustomImageFilename(basename);
1167 if (filename == NULL) /* (should never happen) */
1169 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1173 if (strEqual(filename, bitmap->source_filename))
1175 /* The old and new image are the same (have the same filename and path).
1176 This usually means that this image does not exist in this graphic set
1177 and a fallback to the existing image is done. */
1182 if ((new_bitmap = LoadImage(filename)) == NULL)
1184 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1188 if (bitmap->width != new_bitmap->width ||
1189 bitmap->height != new_bitmap->height)
1191 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1193 FreeBitmap(new_bitmap);
1197 TransferBitmapPointers(new_bitmap, bitmap);
1201 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1203 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1206 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1208 if (bitmaps[IMG_BITMAP_CUSTOM])
1210 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1212 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1215 if (gfx.game_tile_size == gfx.standard_tile_size)
1217 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1222 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1223 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1224 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1226 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1228 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1229 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1232 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1233 int tile_size, boolean create_small_bitmaps)
1235 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1236 Bitmap *tmp_bitmap_final = NULL;
1237 Bitmap *tmp_bitmap_0 = NULL;
1238 Bitmap *tmp_bitmap_1 = NULL;
1239 Bitmap *tmp_bitmap_2 = NULL;
1240 Bitmap *tmp_bitmap_4 = NULL;
1241 Bitmap *tmp_bitmap_8 = NULL;
1242 Bitmap *tmp_bitmap_16 = NULL;
1243 Bitmap *tmp_bitmap_32 = NULL;
1244 int width_final, height_final;
1245 int width_0, height_0;
1246 int width_1, height_1;
1247 int width_2, height_2;
1248 int width_4, height_4;
1249 int width_8, height_8;
1250 int width_16, height_16;
1251 int width_32, height_32;
1252 int old_width, old_height;
1255 print_timestamp_init("CreateScaledBitmaps");
1257 old_width = old_bitmap->width;
1258 old_height = old_bitmap->height;
1260 /* calculate new image dimensions for final image size */
1261 width_final = old_width * zoom_factor;
1262 height_final = old_height * zoom_factor;
1264 /* get image with final size (this might require scaling up) */
1265 /* ("final" size may result in non-standard tile size image) */
1266 if (zoom_factor != 1)
1267 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1269 tmp_bitmap_final = old_bitmap;
1271 UPDATE_BUSY_STATE();
1273 width_0 = width_1 = width_final;
1274 height_0 = height_1 = height_final;
1276 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1278 if (create_small_bitmaps)
1280 /* check if we have a non-gameplay tile size image */
1281 if (tile_size != gfx.game_tile_size)
1283 /* get image with gameplay tile size */
1284 width_0 = width_final * gfx.game_tile_size / tile_size;
1285 height_0 = height_final * gfx.game_tile_size / tile_size;
1287 if (width_0 == old_width)
1288 tmp_bitmap_0 = old_bitmap;
1289 else if (width_0 == width_final)
1290 tmp_bitmap_0 = tmp_bitmap_final;
1292 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1294 UPDATE_BUSY_STATE();
1297 /* check if we have a non-standard tile size image */
1298 if (tile_size != gfx.standard_tile_size)
1300 /* get image with standard tile size */
1301 width_1 = width_final * gfx.standard_tile_size / tile_size;
1302 height_1 = height_final * gfx.standard_tile_size / tile_size;
1304 if (width_1 == old_width)
1305 tmp_bitmap_1 = old_bitmap;
1306 else if (width_1 == width_final)
1307 tmp_bitmap_1 = tmp_bitmap_final;
1308 else if (width_1 == width_0)
1309 tmp_bitmap_1 = tmp_bitmap_0;
1311 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1313 UPDATE_BUSY_STATE();
1316 /* calculate new image dimensions for small images */
1317 width_2 = width_1 / 2;
1318 height_2 = height_1 / 2;
1319 width_4 = width_1 / 4;
1320 height_4 = height_1 / 4;
1321 width_8 = width_1 / 8;
1322 height_8 = height_1 / 8;
1323 width_16 = width_1 / 16;
1324 height_16 = height_1 / 16;
1325 width_32 = width_1 / 32;
1326 height_32 = height_1 / 32;
1328 /* get image with 1/2 of normal size (for use in the level editor) */
1329 if (width_2 == old_width)
1330 tmp_bitmap_2 = old_bitmap;
1332 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1334 UPDATE_BUSY_STATE();
1336 /* get image with 1/4 of normal size (for use in the level editor) */
1337 if (width_4 == old_width)
1338 tmp_bitmap_4 = old_bitmap;
1340 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1342 UPDATE_BUSY_STATE();
1344 /* get image with 1/8 of normal size (for use on the preview screen) */
1345 if (width_8 == old_width)
1346 tmp_bitmap_8 = old_bitmap;
1348 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1350 UPDATE_BUSY_STATE();
1352 /* get image with 1/16 of normal size (for use on the preview screen) */
1353 if (width_16 == old_width)
1354 tmp_bitmap_16 = old_bitmap;
1356 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1358 UPDATE_BUSY_STATE();
1360 /* get image with 1/32 of normal size (for use on the preview screen) */
1361 if (width_32 == old_width)
1362 tmp_bitmap_32 = old_bitmap;
1364 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1366 UPDATE_BUSY_STATE();
1368 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1369 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1370 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1371 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1372 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1373 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1375 if (width_0 != width_1)
1376 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1378 if (bitmaps[IMG_BITMAP_CUSTOM])
1379 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1381 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1383 boolean free_old_bitmap = TRUE;
1385 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1386 if (bitmaps[i] == old_bitmap)
1387 free_old_bitmap = FALSE;
1389 if (free_old_bitmap)
1390 FreeBitmap(old_bitmap);
1394 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1397 UPDATE_BUSY_STATE();
1399 print_timestamp_done("CreateScaledBitmaps");
1402 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1405 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1408 void CreateBitmapTextures(Bitmap **bitmaps)
1410 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1413 void FreeBitmapTextures(Bitmap **bitmaps)
1415 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1418 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1420 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1424 /* ------------------------------------------------------------------------- */
1425 /* mouse pointer functions */
1426 /* ------------------------------------------------------------------------- */
1428 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1430 /* XPM image definitions */
1431 static const char *cursor_image_none[] =
1433 /* width height num_colors chars_per_pixel */
1463 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1464 static const char *cursor_image_dot[] =
1466 /* width height num_colors chars_per_pixel */
1495 static const char **cursor_image_playfield = cursor_image_dot;
1497 /* some people complained about a "white dot" on the screen and thought it
1498 was a graphical error... OK, let's just remove the whole pointer :-) */
1499 static const char **cursor_image_playfield = cursor_image_none;
1502 static const int cursor_bit_order = BIT_ORDER_MSB;
1504 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1506 struct MouseCursorInfo *cursor;
1507 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1508 int header_lines = 4;
1511 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1513 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1516 for (y = 0; y < cursor->width; y++)
1518 for (x = 0; x < cursor->height; x++)
1521 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1526 cursor->data[i] = cursor->mask[i] = 0;
1529 switch (image[header_lines + y][x])
1532 cursor->data[i] |= bit_mask;
1533 cursor->mask[i] |= bit_mask;
1537 cursor->mask[i] |= bit_mask;
1546 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1551 void SetMouseCursor(int mode)
1553 static struct MouseCursorInfo *cursor_none = NULL;
1554 static struct MouseCursorInfo *cursor_playfield = NULL;
1555 struct MouseCursorInfo *cursor_new;
1557 if (cursor_none == NULL)
1558 cursor_none = get_cursor_from_image(cursor_image_none);
1560 if (cursor_playfield == NULL)
1561 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1563 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1564 mode == CURSOR_NONE ? cursor_none :
1565 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1567 SDLSetMouseCursor(cursor_new);
1569 gfx.cursor_mode = mode;
1573 /* ========================================================================= */
1574 /* audio functions */
1575 /* ========================================================================= */
1577 void OpenAudio(void)
1579 /* always start with reliable default values */
1580 audio.sound_available = FALSE;
1581 audio.music_available = FALSE;
1582 audio.loops_available = FALSE;
1584 audio.sound_enabled = FALSE;
1585 audio.sound_deactivated = FALSE;
1587 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1588 audio.mixer_pid = 0;
1589 audio.device_name = NULL;
1590 audio.device_fd = -1;
1592 audio.num_channels = 0;
1593 audio.music_channel = 0;
1594 audio.first_sound_channel = 0;
1599 void CloseAudio(void)
1603 audio.sound_enabled = FALSE;
1606 void SetAudioMode(boolean enabled)
1608 if (!audio.sound_available)
1611 audio.sound_enabled = enabled;
1615 /* ========================================================================= */
1616 /* event functions */
1617 /* ========================================================================= */
1619 boolean PendingEvent(void)
1621 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1624 void WaitEvent(Event *event)
1626 SDLWaitEvent(event);
1629 void PeekEvent(Event *event)
1631 #if defined(TARGET_SDL2)
1632 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1634 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1638 void CheckQuitEvent(void)
1640 if (SDL_QuitRequested())
1641 program.exit_function(0);
1644 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1646 #if defined(TARGET_SDL2)
1647 /* key up/down events in SDL2 do not return text characters anymore */
1648 return event->keysym.sym;
1651 #if ENABLE_UNUSED_CODE
1652 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1653 (int)event->keysym.unicode,
1654 (int)event->keysym.sym,
1655 (int)SDL_GetModState());
1658 if (with_modifiers &&
1659 event->keysym.unicode > 0x0000 &&
1660 event->keysym.unicode < 0x2000)
1661 return event->keysym.unicode;
1663 return event->keysym.sym;
1668 KeyMod HandleKeyModState(Key key, int key_status)
1670 static KeyMod current_modifiers = KMOD_None;
1672 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1674 KeyMod new_modifier = KMOD_None;
1679 new_modifier = KMOD_Shift_L;
1682 new_modifier = KMOD_Shift_R;
1684 case KSYM_Control_L:
1685 new_modifier = KMOD_Control_L;
1687 case KSYM_Control_R:
1688 new_modifier = KMOD_Control_R;
1691 new_modifier = KMOD_Meta_L;
1694 new_modifier = KMOD_Meta_R;
1697 new_modifier = KMOD_Alt_L;
1700 new_modifier = KMOD_Alt_R;
1706 if (key_status == KEY_PRESSED)
1707 current_modifiers |= new_modifier;
1709 current_modifiers &= ~new_modifier;
1712 return current_modifiers;
1715 KeyMod GetKeyModState()
1717 return (KeyMod)SDL_GetModState();
1720 KeyMod GetKeyModStateFromEvents()
1722 /* always use key modifier state as tracked from key events (this is needed
1723 if the modifier key event was injected into the event queue, but the key
1724 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1725 query the keys as held pressed on the keyboard) -- this case is currently
1726 only used to filter out clipboard insert events from "True X-Mouse" tool */
1728 return HandleKeyModState(KSYM_UNDEFINED, 0);
1731 void StartTextInput(int x, int y, int width, int height)
1733 #if defined(TARGET_SDL2)
1734 #if defined(HAS_SCREEN_KEYBOARD)
1735 SDL_StartTextInput();
1737 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1739 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1740 video.shifted_up_delay = SDL_GetTicks();
1741 video.shifted_up = TRUE;
1747 void StopTextInput()
1749 #if defined(TARGET_SDL2)
1750 #if defined(HAS_SCREEN_KEYBOARD)
1751 SDL_StopTextInput();
1753 if (video.shifted_up)
1755 video.shifted_up_pos = 0;
1756 video.shifted_up_delay = SDL_GetTicks();
1757 video.shifted_up = FALSE;
1763 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1765 if (event->type != EVENT_CLIENTMESSAGE)
1768 return TRUE; /* the only possible message here is SDL_QUIT */
1772 /* ========================================================================= */
1773 /* joystick functions */
1774 /* ========================================================================= */
1776 void InitJoysticks()
1780 #if defined(NO_JOYSTICK)
1781 return; /* joysticks generally deactivated by compile-time directive */
1784 /* always start with reliable default values */
1785 joystick.status = JOYSTICK_NOT_AVAILABLE;
1786 for (i = 0; i < MAX_PLAYERS; i++)
1787 joystick.nr[i] = -1; /* no joystick configured */
1792 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1794 return SDLReadJoystick(nr, x, y, b1, b2);
1797 boolean CheckJoystickOpened(int nr)
1799 return SDLCheckJoystickOpened(nr);
1802 void ClearJoystickState()
1804 SDLClearJoystickState();