1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct RuntimeInfo runtime;
34 struct OptionInfo options;
35 struct VideoSystemInfo video;
36 struct AudioSystemInfo audio;
38 struct TileCursorInfo tile_cursor;
39 struct OverlayInfo overlay;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
44 LevelDirTree *leveldir_first_all = NULL;
45 LevelDirTree *leveldir_first = NULL;
46 LevelDirTree *leveldir_current = NULL;
49 struct LevelSetInfo levelset;
50 struct LevelStats level_stats[MAX_LEVELS];
52 DrawWindow *window = NULL;
53 DrawBuffer *backbuffer = NULL;
54 DrawBuffer *drawto = NULL;
56 int button_status = MB_NOT_PRESSED;
57 boolean motion_status = FALSE;
58 int wheel_steps = DEFAULT_WHEEL_STEPS;
59 boolean keyrepeat_status = TRUE;
60 boolean textinput_status = FALSE;
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 InitRuntimeInfo()
121 #if defined(HAS_TOUCH_DEVICE)
122 runtime.uses_touch_device = TRUE;
124 runtime.uses_touch_device = FALSE;
128 void InitScoresInfo(void)
130 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
132 program.global_scores = directoryExists(global_scores_dir);
133 program.many_scores_per_name = !program.global_scores;
138 if (program.global_scores)
140 Debug("internal:path", "Using global, multi-user scores directory '%s'.",
142 Debug("internal:path", "Remove to enable single-user scores directory.");
143 Debug("internal:path", "(This enables multipe score entries per user.)");
147 Debug("internal:path", "Using private, single-user scores directory.");
152 free(global_scores_dir);
155 void SetWindowTitle(void)
157 program.window_title = program.window_title_function();
162 void InitWindowTitleFunction(char *(*window_title_function)(void))
164 program.window_title_function = window_title_function;
167 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
169 program.exit_message_function = exit_message_function;
172 void InitExitFunction(void (*exit_function)(int))
174 program.exit_function = exit_function;
176 // set signal handlers to custom exit function
177 // signal(SIGINT, exit_function);
178 signal(SIGTERM, exit_function);
180 // set exit function to automatically cleanup SDL stuff after exit()
184 void InitPlatformDependentStuff(void)
186 // this is initialized in GetOptions(), but may already be used before
187 options.verbose = TRUE;
191 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
193 if (SDL_Init(sdl_init_flags) < 0)
194 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
199 void ClosePlatformDependentStuff(void)
204 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
205 int real_sx, int real_sy,
206 int full_sxsize, int full_sysize,
207 Bitmap *field_save_buffer)
213 gfx.real_sx = real_sx;
214 gfx.real_sy = real_sy;
215 gfx.full_sxsize = full_sxsize;
216 gfx.full_sysize = full_sysize;
218 gfx.field_save_buffer = field_save_buffer;
220 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
221 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
224 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
226 gfx.game_tile_size = game_tile_size;
227 gfx.standard_tile_size = standard_tile_size;
230 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
238 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
246 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
254 void InitGfxWindowInfo(int win_xsize, int win_ysize)
256 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
258 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
260 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
262 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
263 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
264 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
265 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
267 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
270 gfx.win_xsize = win_xsize;
271 gfx.win_ysize = win_ysize;
273 gfx.background_bitmap_mask = REDRAW_NONE;
276 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
278 // currently only used by MSDOS code to alloc VRAM buffer, if available
279 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
280 gfx.scrollbuffer_width = scrollbuffer_width;
281 gfx.scrollbuffer_height = scrollbuffer_height;
284 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
286 gfx.clipping_enabled = enabled;
289 gfx.clip_width = width;
290 gfx.clip_height = height;
293 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
295 gfx.draw_busy_anim_function = draw_busy_anim_function;
298 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
300 gfx.draw_global_anim_function = draw_global_anim_function;
303 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
305 gfx.draw_global_border_function = draw_global_border_function;
308 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
310 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
313 void InitGfxCustomArtworkInfo(void)
315 gfx.override_level_graphics = FALSE;
316 gfx.override_level_sounds = FALSE;
317 gfx.override_level_music = FALSE;
319 gfx.draw_init_text = TRUE;
322 void InitGfxOtherSettings(void)
324 gfx.cursor_mode = CURSOR_DEFAULT;
325 gfx.cursor_mode_override = CURSOR_UNDEFINED;
326 gfx.cursor_mode_final = gfx.cursor_mode;
328 // prevent initially displaying custom mouse cursor in upper left corner
329 gfx.mouse_x = POS_OFFSCREEN;
330 gfx.mouse_y = POS_OFFSCREEN;
333 void InitTileCursorInfo(void)
335 tile_cursor.enabled = FALSE;
336 tile_cursor.active = FALSE;
337 tile_cursor.moving = FALSE;
339 tile_cursor.xpos = 0;
340 tile_cursor.ypos = 0;
343 tile_cursor.target_x = 0;
344 tile_cursor.target_y = 0;
350 void InitOverlayInfo(void)
352 int nr = GRID_ACTIVE_NR();
355 overlay.enabled = FALSE;
356 overlay.active = FALSE;
358 overlay.show_grid = FALSE;
360 overlay.grid_xsize = setup.touch.grid_xsize[nr];
361 overlay.grid_ysize = setup.touch.grid_ysize[nr];
363 for (x = 0; x < MAX_GRID_XSIZE; x++)
364 for (y = 0; y < MAX_GRID_YSIZE; y++)
365 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
367 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
368 overlay.grid_button_action = JOY_NO_ACTION;
370 #if defined(USE_TOUCH_INPUT_OVERLAY)
371 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
372 overlay.enabled = TRUE;
376 void SetTileCursorEnabled(boolean enabled)
378 tile_cursor.enabled = enabled;
381 void SetTileCursorActive(boolean active)
383 tile_cursor.active = active;
386 void SetTileCursorTargetXY(int x, int y)
388 // delayed placement of tile selection cursor at target position
389 // (tile cursor will be moved to target position step by step)
391 tile_cursor.xpos = x;
392 tile_cursor.ypos = y;
393 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
394 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
396 tile_cursor.moving = TRUE;
399 void SetTileCursorXY(int x, int y)
401 // immediate placement of tile selection cursor at target position
403 SetTileCursorTargetXY(x, y);
405 tile_cursor.x = tile_cursor.target_x;
406 tile_cursor.y = tile_cursor.target_y;
408 tile_cursor.moving = FALSE;
411 void SetTileCursorSXSY(int sx, int sy)
417 void SetOverlayEnabled(boolean enabled)
419 overlay.enabled = enabled;
422 void SetOverlayActive(boolean active)
424 overlay.active = active;
427 void SetOverlayShowGrid(boolean show_grid)
429 overlay.show_grid = show_grid;
431 SetOverlayActive(show_grid);
434 SetOverlayEnabled(TRUE);
437 boolean GetOverlayEnabled(void)
439 return overlay.enabled;
442 boolean GetOverlayActive(void)
444 return overlay.active;
447 void SetDrawDeactivationMask(int draw_deactivation_mask)
449 gfx.draw_deactivation_mask = draw_deactivation_mask;
452 int GetDrawDeactivationMask(void)
454 return gfx.draw_deactivation_mask;
457 void SetDrawBackgroundMask(int draw_background_mask)
459 gfx.draw_background_mask = draw_background_mask;
462 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
464 if (background_bitmap_tile != NULL)
465 gfx.background_bitmap_mask |= mask;
467 gfx.background_bitmap_mask &= ~mask;
469 if (background_bitmap_tile == NULL) // empty background requested
472 if (mask == REDRAW_ALL)
473 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
474 0, 0, video.width, video.height);
475 else if (mask == REDRAW_FIELD)
476 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
477 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
478 else if (mask == REDRAW_DOOR_1)
479 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
480 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
483 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
485 // remove every mask before setting mask for window
486 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
487 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
488 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
491 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
493 // remove window area mask before setting mask for main area
494 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
495 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
496 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
499 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
501 // remove window area mask before setting mask for door area
502 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
503 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
504 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
508 // ============================================================================
510 // ============================================================================
512 static int GetRealDepth(int depth)
514 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
517 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
518 int width, int height, Pixel color)
520 SDLFillRectangle(bitmap, x, y, width, height, color);
522 if (bitmap == backbuffer)
523 SetRedrawMaskFromArea(x, y, width, height);
526 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
527 int src_x, int src_y, int width, int height,
528 int dst_x, int dst_y, int mask_mode)
530 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
531 dst_x, dst_y, mask_mode);
533 if (dst_bitmap == backbuffer)
534 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
537 void LimitScreenUpdates(boolean enable)
539 SDLLimitScreenUpdates(enable);
542 void InitVideoDefaults(void)
544 video.default_depth = 32;
547 void InitVideoDisplay(void)
549 if (program.headless)
552 SDLInitVideoDisplay();
556 void CloseVideoDisplay(void)
558 KeyboardAutoRepeatOn();
560 SDL_QuitSubSystem(SDL_INIT_VIDEO);
563 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
566 video.height = height;
567 video.depth = GetRealDepth(depth);
569 video.screen_width = width;
570 video.screen_height = height;
571 video.screen_xoffset = 0;
572 video.screen_yoffset = 0;
574 video.fullscreen_available = FULLSCREEN_STATUS;
575 video.fullscreen_enabled = FALSE;
577 video.window_scaling_available = WINDOW_SCALING_STATUS;
579 video.frame_counter = 0;
580 video.frame_delay = 0;
581 video.frame_delay_value = GAME_FRAME_DELAY;
583 video.shifted_up = FALSE;
584 video.shifted_up_pos = 0;
585 video.shifted_up_pos_last = 0;
586 video.shifted_up_delay = 0;
587 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
589 SDLInitVideoBuffer(fullscreen);
591 video.initialized = !program.headless;
596 static void FreeBitmapPointers(Bitmap *bitmap)
601 SDLFreeBitmapPointers(bitmap);
603 checked_free(bitmap->source_filename);
604 bitmap->source_filename = NULL;
607 static void TransferBitmapPointers(Bitmap *src_bitmap,
610 if (src_bitmap == NULL || dst_bitmap == NULL)
613 FreeBitmapPointers(dst_bitmap);
615 *dst_bitmap = *src_bitmap;
618 void FreeBitmap(Bitmap *bitmap)
623 FreeBitmapPointers(bitmap);
628 Bitmap *CreateBitmapStruct(void)
630 return checked_calloc(sizeof(Bitmap));
633 Bitmap *CreateBitmap(int width, int height, int depth)
635 Bitmap *new_bitmap = CreateBitmapStruct();
636 int real_width = MAX(1, width); // prevent zero bitmap width
637 int real_height = MAX(1, height); // prevent zero bitmap height
638 int real_depth = GetRealDepth(depth);
640 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
642 new_bitmap->width = real_width;
643 new_bitmap->height = real_height;
648 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
652 // if new bitmap size fits into old one, no need to re-create it
653 if (width <= (*bitmap)->width &&
654 height <= (*bitmap)->height)
657 // else adjust size so that old and new bitmap size fit into it
658 width = MAX(width, (*bitmap)->width);
659 height = MAX(height, (*bitmap)->height);
662 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
666 *bitmap = new_bitmap;
670 TransferBitmapPointers(new_bitmap, *bitmap);
676 static void CloseWindow(DrawWindow *window)
681 void SetRedrawMaskFromArea(int x, int y, int width, int height)
685 int x2 = x + width - 1;
686 int y2 = y + height - 1;
688 if (width == 0 || height == 0)
691 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
692 redraw_mask |= REDRAW_FIELD;
693 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
694 redraw_mask |= REDRAW_DOOR_1;
695 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
696 redraw_mask |= REDRAW_DOOR_2;
697 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
698 redraw_mask |= REDRAW_DOOR_3;
700 redraw_mask = REDRAW_ALL;
703 static boolean CheckDrawingArea(int x, int y, int width, int height,
706 if (draw_mask == REDRAW_NONE)
709 if (draw_mask & REDRAW_ALL)
712 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
715 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
718 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
721 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
727 boolean DrawingDeactivatedField(void)
729 if (program.headless)
732 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
738 boolean DrawingDeactivated(int x, int y, int width, int height)
740 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
743 boolean DrawingOnBackground(int x, int y)
745 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
746 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
749 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
750 int *width, int *height, boolean is_dest)
752 int clip_x, clip_y, clip_width, clip_height;
754 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
756 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
757 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
758 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
759 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
765 clip_width = bitmap->width;
766 clip_height = bitmap->height;
769 // skip if rectangle completely outside bitmap
771 if (*x + *width <= clip_x ||
772 *y + *height <= clip_y ||
773 *x >= clip_x + clip_width ||
774 *y >= clip_y + clip_height)
777 // clip if rectangle overlaps bitmap
781 *width -= clip_x - *x;
784 else if (*x + *width > clip_x + clip_width)
786 *width = clip_x + clip_width - *x;
791 *height -= clip_y - *y;
794 else if (*y + *height > clip_y + clip_height)
796 *height = clip_y + clip_height - *y;
802 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
803 int src_x, int src_y, int width, int height,
804 int dst_x, int dst_y)
806 int dst_x_unclipped = dst_x;
807 int dst_y_unclipped = dst_y;
809 if (program.headless)
812 if (src_bitmap == NULL || dst_bitmap == NULL)
815 if (DrawingDeactivated(dst_x, dst_y, width, height))
818 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
819 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
822 // source x/y might need adjustment if destination x/y was clipped top/left
823 src_x += dst_x - dst_x_unclipped;
824 src_y += dst_y - dst_y_unclipped;
826 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
827 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
828 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
829 but is already fixed in SVN and should therefore finally be fixed with
830 the next official SDL release, which is probably version 1.2.14.) */
831 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
833 if (src_bitmap == dst_bitmap)
835 // needed when blitting directly to same bitmap -- should not be needed with
836 // recent SDL libraries, but apparently does not work in 1.2.11 directly
838 static Bitmap *tmp_bitmap = NULL;
839 static int tmp_bitmap_xsize = 0;
840 static int tmp_bitmap_ysize = 0;
842 // start with largest static bitmaps for initial bitmap size ...
843 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
845 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
846 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
849 // ... and allow for later re-adjustments due to custom artwork bitmaps
850 if (src_bitmap->width > tmp_bitmap_xsize ||
851 src_bitmap->height > tmp_bitmap_ysize)
853 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
854 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
856 FreeBitmap(tmp_bitmap);
861 if (tmp_bitmap == NULL)
862 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
865 sysCopyArea(src_bitmap, tmp_bitmap,
866 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
867 sysCopyArea(tmp_bitmap, dst_bitmap,
868 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
873 sysCopyArea(src_bitmap, dst_bitmap,
874 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
877 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
878 int src_x, int src_y, int src_width, int src_height,
879 int dst_x, int dst_y, int dst_width, int dst_height)
881 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
882 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
883 int dst_xsize = dst_width;
884 int dst_ysize = dst_height;
885 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
886 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
889 for (y = 0; y < src_ysteps; y++)
891 for (x = 0; x < src_xsteps; x++)
893 int draw_x = dst_x + x * src_xsize;
894 int draw_y = dst_y + y * src_ysize;
895 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
896 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
898 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
904 void FadeRectangle(int x, int y, int width, int height,
905 int fade_mode, int fade_delay, int post_delay,
906 void (*draw_border_function)(void))
908 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
909 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
912 SDLFadeRectangle(x, y, width, height,
913 fade_mode, fade_delay, post_delay, draw_border_function);
916 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
919 if (DrawingDeactivated(x, y, width, height))
922 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
925 sysFillRectangle(bitmap, x, y, width, height, color);
928 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
930 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
933 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
934 int width, int height)
936 if (DrawingOnBackground(x, y))
937 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
939 ClearRectangle(bitmap, x, y, width, height);
942 void BlitBitmapMasked(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 (DrawingDeactivated(dst_x, dst_y, width, height))
949 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
950 dst_x, dst_y, BLIT_MASKED);
953 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
954 int src_x, int src_y, int width, int height,
955 int dst_x, int dst_y)
957 if (DrawingOnBackground(dst_x, dst_y))
960 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
964 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
968 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
972 void BlitTexture(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 BlitTextureMasked(Bitmap *bitmap,
984 int src_x, int src_y, int width, int height,
985 int dst_x, int dst_y)
990 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
994 void BlitToScreen(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 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1003 width, height, dst_x, dst_y);
1005 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1008 void BlitToScreenMasked(Bitmap *bitmap,
1009 int src_x, int src_y, int width, int height,
1010 int dst_x, int dst_y)
1015 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1016 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1017 width, height, dst_x, dst_y);
1019 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1022 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1025 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1028 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1031 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1034 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1035 int to_x, int to_y, Pixel pixel, int line_width)
1039 if (program.headless)
1042 for (x = 0; x < line_width; x++)
1044 for (y = 0; y < line_width; y++)
1046 int dx = x - line_width / 2;
1047 int dy = y - line_width / 2;
1049 if ((x == 0 && y == 0) ||
1050 (x == 0 && y == line_width - 1) ||
1051 (x == line_width - 1 && y == 0) ||
1052 (x == line_width - 1 && y == line_width - 1))
1056 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1061 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1066 for (i = 0; i < num_points - 1; i++)
1067 DrawLine(bitmap, points[i].x, points[i].y,
1068 points[i + 1].x, points[i + 1].y, pixel, line_width);
1071 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1075 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1077 if (program.headless)
1080 if (x < 0 || x >= bitmap->width ||
1081 y < 0 || y >= bitmap->height)
1084 return SDLGetPixel(bitmap, x, y);
1087 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1088 unsigned int color_g, unsigned int color_b)
1090 if (program.headless)
1093 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1096 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1098 unsigned int color_r = (color >> 16) & 0xff;
1099 unsigned int color_g = (color >> 8) & 0xff;
1100 unsigned int color_b = (color >> 0) & 0xff;
1102 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1105 void KeyboardAutoRepeatOn(void)
1107 keyrepeat_status = TRUE;
1110 void KeyboardAutoRepeatOff(void)
1112 keyrepeat_status = FALSE;
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 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1177 if (strEqual(filename, bitmap->source_filename))
1179 // The old and new image are the same (have the same filename and path).
1180 // This usually means that this image does not exist in this graphic set
1181 // and a fallback to the existing image is done.
1186 if ((new_bitmap = LoadImage(filename)) == NULL)
1188 Warn("LoadImage('%s') failed: %s", basename, GetError());
1193 if (bitmap->width != new_bitmap->width ||
1194 bitmap->height != new_bitmap->height)
1196 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1199 FreeBitmap(new_bitmap);
1204 TransferBitmapPointers(new_bitmap, bitmap);
1208 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1210 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1213 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1215 if (bitmaps[IMG_BITMAP_CUSTOM])
1217 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1219 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1222 if (gfx.game_tile_size == gfx.standard_tile_size)
1224 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1229 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1230 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1231 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1233 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1235 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1236 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1239 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1240 int tile_size, boolean create_small_bitmaps)
1242 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1243 Bitmap *tmp_bitmap_final = NULL;
1244 Bitmap *tmp_bitmap_0 = NULL;
1245 Bitmap *tmp_bitmap_1 = NULL;
1246 Bitmap *tmp_bitmap_2 = NULL;
1247 Bitmap *tmp_bitmap_4 = NULL;
1248 Bitmap *tmp_bitmap_8 = NULL;
1249 Bitmap *tmp_bitmap_16 = NULL;
1250 Bitmap *tmp_bitmap_32 = NULL;
1251 int width_final, height_final;
1252 int width_0, height_0;
1253 int width_1, height_1;
1254 int width_2, height_2;
1255 int width_4, height_4;
1256 int width_8, height_8;
1257 int width_16, height_16;
1258 int width_32, height_32;
1259 int old_width, old_height;
1262 print_timestamp_init("CreateScaledBitmaps");
1264 old_width = old_bitmap->width;
1265 old_height = old_bitmap->height;
1267 // calculate new image dimensions for final image size
1268 width_final = old_width * zoom_factor;
1269 height_final = old_height * zoom_factor;
1271 // get image with final size (this might require scaling up)
1272 // ("final" size may result in non-standard tile size image)
1273 if (zoom_factor != 1)
1274 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1276 tmp_bitmap_final = old_bitmap;
1278 UPDATE_BUSY_STATE();
1280 width_0 = width_1 = width_final;
1281 height_0 = height_1 = height_final;
1283 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1285 if (create_small_bitmaps)
1287 // check if we have a non-gameplay tile size image
1288 if (tile_size != gfx.game_tile_size)
1290 // get image with gameplay tile size
1291 width_0 = width_final * gfx.game_tile_size / tile_size;
1292 height_0 = height_final * gfx.game_tile_size / tile_size;
1294 if (width_0 == old_width)
1295 tmp_bitmap_0 = old_bitmap;
1296 else if (width_0 == width_final)
1297 tmp_bitmap_0 = tmp_bitmap_final;
1299 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1301 UPDATE_BUSY_STATE();
1304 // check if we have a non-standard tile size image
1305 if (tile_size != gfx.standard_tile_size)
1307 // get image with standard tile size
1308 width_1 = width_final * gfx.standard_tile_size / tile_size;
1309 height_1 = height_final * gfx.standard_tile_size / tile_size;
1311 if (width_1 == old_width)
1312 tmp_bitmap_1 = old_bitmap;
1313 else if (width_1 == width_final)
1314 tmp_bitmap_1 = tmp_bitmap_final;
1315 else if (width_1 == width_0)
1316 tmp_bitmap_1 = tmp_bitmap_0;
1318 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1320 UPDATE_BUSY_STATE();
1323 // calculate new image dimensions for small images
1324 width_2 = width_1 / 2;
1325 height_2 = height_1 / 2;
1326 width_4 = width_1 / 4;
1327 height_4 = height_1 / 4;
1328 width_8 = width_1 / 8;
1329 height_8 = height_1 / 8;
1330 width_16 = width_1 / 16;
1331 height_16 = height_1 / 16;
1332 width_32 = width_1 / 32;
1333 height_32 = height_1 / 32;
1335 // get image with 1/2 of normal size (for use in the level editor)
1336 if (width_2 == old_width)
1337 tmp_bitmap_2 = old_bitmap;
1339 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1341 UPDATE_BUSY_STATE();
1343 // get image with 1/4 of normal size (for use in the level editor)
1344 if (width_4 == old_width)
1345 tmp_bitmap_4 = old_bitmap;
1347 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1349 UPDATE_BUSY_STATE();
1351 // get image with 1/8 of normal size (for use on the preview screen)
1352 if (width_8 == old_width)
1353 tmp_bitmap_8 = old_bitmap;
1355 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1357 UPDATE_BUSY_STATE();
1359 // get image with 1/16 of normal size (for use on the preview screen)
1360 if (width_16 == old_width)
1361 tmp_bitmap_16 = old_bitmap;
1363 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1365 UPDATE_BUSY_STATE();
1367 // get image with 1/32 of normal size (for use on the preview screen)
1368 if (width_32 == old_width)
1369 tmp_bitmap_32 = old_bitmap;
1371 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1373 UPDATE_BUSY_STATE();
1375 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1376 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1377 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1378 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1379 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1380 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1382 if (width_0 != width_1)
1383 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1385 if (bitmaps[IMG_BITMAP_CUSTOM])
1386 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1388 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1390 boolean free_old_bitmap = TRUE;
1392 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1393 if (bitmaps[i] == old_bitmap)
1394 free_old_bitmap = FALSE;
1396 if (free_old_bitmap)
1398 // copy image filename from old to new standard sized bitmap
1399 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1400 getStringCopy(old_bitmap->source_filename);
1402 FreeBitmap(old_bitmap);
1407 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1410 UPDATE_BUSY_STATE();
1412 print_timestamp_done("CreateScaledBitmaps");
1415 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1418 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1421 void CreateBitmapTextures(Bitmap **bitmaps)
1423 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1426 void FreeBitmapTextures(Bitmap **bitmaps)
1428 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1431 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1433 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1437 // ----------------------------------------------------------------------------
1438 // mouse pointer functions
1439 // ----------------------------------------------------------------------------
1441 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1443 // XPM image definitions
1444 static const char *cursor_image_none[] =
1446 // width height num_colors chars_per_pixel
1476 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1477 static const char *cursor_image_dot[] =
1479 // width height num_colors chars_per_pixel
1508 static const char **cursor_image_playfield = cursor_image_dot;
1510 // some people complained about a "white dot" on the screen and thought it
1511 // was a graphical error... OK, let's just remove the whole pointer :-)
1512 static const char **cursor_image_playfield = cursor_image_none;
1515 static const int cursor_bit_order = BIT_ORDER_MSB;
1517 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1519 struct MouseCursorInfo *cursor;
1520 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1521 int header_lines = 4;
1524 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1526 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1529 for (y = 0; y < cursor->width; y++)
1531 for (x = 0; x < cursor->height; x++)
1534 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1539 cursor->data[i] = cursor->mask[i] = 0;
1542 switch (image[header_lines + y][x])
1545 cursor->data[i] |= bit_mask;
1546 cursor->mask[i] |= bit_mask;
1550 cursor->mask[i] |= bit_mask;
1559 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1564 void SetMouseCursor(int mode)
1566 static struct MouseCursorInfo *cursor_none = NULL;
1567 static struct MouseCursorInfo *cursor_playfield = NULL;
1568 struct MouseCursorInfo *cursor_new;
1569 int mode_final = mode;
1571 if (cursor_none == NULL)
1572 cursor_none = get_cursor_from_image(cursor_image_none);
1574 if (cursor_playfield == NULL)
1575 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1577 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1578 mode_final = gfx.cursor_mode_override;
1580 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1581 mode_final == CURSOR_NONE ? cursor_none :
1582 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1584 SDLSetMouseCursor(cursor_new);
1586 gfx.cursor_mode = mode;
1587 gfx.cursor_mode_final = mode_final;
1590 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1592 // mouse events do not contain logical screen size corrections yet
1593 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1595 mouse_x -= video.screen_xoffset;
1596 mouse_y -= video.screen_yoffset;
1598 gfx.mouse_x = mouse_x;
1599 gfx.mouse_y = mouse_y;
1602 void UpdateMousePosition(void)
1604 int mouse_x, mouse_y;
1607 SDL_GetMouseState(&mouse_x, &mouse_y);
1609 UpdateRawMousePosition(mouse_x, mouse_y);
1613 // ============================================================================
1615 // ============================================================================
1617 void OpenAudio(void)
1619 // always start with reliable default values
1620 audio.sound_available = FALSE;
1621 audio.music_available = FALSE;
1622 audio.loops_available = FALSE;
1624 audio.sound_enabled = FALSE;
1625 audio.sound_deactivated = FALSE;
1627 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1628 audio.mixer_pid = 0;
1629 audio.device_name = NULL;
1630 audio.device_fd = -1;
1632 audio.num_channels = 0;
1633 audio.music_channel = 0;
1634 audio.first_sound_channel = 0;
1639 void CloseAudio(void)
1643 audio.sound_enabled = FALSE;
1646 void SetAudioMode(boolean enabled)
1648 if (!audio.sound_available)
1651 audio.sound_enabled = enabled;
1655 // ============================================================================
1657 // ============================================================================
1659 void InitEventFilter(EventFilter filter_function)
1661 SDL_SetEventFilter(filter_function, NULL);
1664 boolean PendingEvent(void)
1666 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1669 void WaitEvent(Event *event)
1671 SDLWaitEvent(event);
1674 void PeekEvent(Event *event)
1676 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1679 void PumpEvents(void)
1684 void CheckQuitEvent(void)
1686 if (SDL_QuitRequested())
1687 program.exit_function(0);
1690 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1692 // key up/down events in SDL2 do not return text characters anymore
1693 return event->keysym.sym;
1696 KeyMod HandleKeyModState(Key key, int key_status)
1698 static KeyMod current_modifiers = KMOD_None;
1700 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1702 KeyMod new_modifier = KMOD_None;
1707 new_modifier = KMOD_Shift_L;
1710 new_modifier = KMOD_Shift_R;
1712 case KSYM_Control_L:
1713 new_modifier = KMOD_Control_L;
1715 case KSYM_Control_R:
1716 new_modifier = KMOD_Control_R;
1719 new_modifier = KMOD_Meta_L;
1722 new_modifier = KMOD_Meta_R;
1725 new_modifier = KMOD_Alt_L;
1728 new_modifier = KMOD_Alt_R;
1734 if (key_status == KEY_PRESSED)
1735 current_modifiers |= new_modifier;
1737 current_modifiers &= ~new_modifier;
1740 return current_modifiers;
1743 KeyMod GetKeyModState(void)
1745 return (KeyMod)SDL_GetModState();
1748 KeyMod GetKeyModStateFromEvents(void)
1750 /* always use key modifier state as tracked from key events (this is needed
1751 if the modifier key event was injected into the event queue, but the key
1752 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1753 query the keys as held pressed on the keyboard) -- this case is currently
1754 only used to filter out clipboard insert events from "True X-Mouse" tool */
1756 return HandleKeyModState(KSYM_UNDEFINED, 0);
1759 void StartTextInput(int x, int y, int width, int height)
1761 textinput_status = TRUE;
1763 #if defined(HAS_SCREEN_KEYBOARD)
1764 SDL_StartTextInput();
1766 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1768 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1769 video.shifted_up_delay = SDL_GetTicks();
1770 video.shifted_up = TRUE;
1775 void StopTextInput(void)
1777 textinput_status = FALSE;
1779 #if defined(HAS_SCREEN_KEYBOARD)
1780 SDL_StopTextInput();
1782 if (video.shifted_up)
1784 video.shifted_up_pos = 0;
1785 video.shifted_up_delay = SDL_GetTicks();
1786 video.shifted_up = FALSE;
1791 void PushUserEvent(int code, int value1, int value2)
1795 SDL_memset(&event, 0, sizeof(event));
1797 event.type = EVENT_USER;
1799 event.value1 = value1;
1800 event.value2 = value2;
1802 SDL_PushEvent((SDL_Event *)&event);
1806 // ============================================================================
1807 // joystick functions
1808 // ============================================================================
1810 void InitJoysticks(void)
1814 #if defined(NO_JOYSTICK)
1815 return; // joysticks generally deactivated by compile-time directive
1818 // always start with reliable default values
1819 joystick.status = JOYSTICK_NOT_AVAILABLE;
1820 for (i = 0; i < MAX_PLAYERS; i++)
1821 joystick.nr[i] = -1; // no joystick configured
1826 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1828 return SDLReadJoystick(nr, x, y, b1, b2);
1831 boolean CheckJoystickOpened(int nr)
1833 return SDLCheckJoystickOpened(nr);
1836 void ClearJoystickState(void)
1838 SDLClearJoystickState();