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 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
142 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
143 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
147 Error(ERR_DEBUG, "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 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;
1565 int mode_final = mode;
1567 if (cursor_none == NULL)
1568 cursor_none = get_cursor_from_image(cursor_image_none);
1570 if (cursor_playfield == NULL)
1571 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1573 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1574 mode_final = gfx.cursor_mode_override;
1576 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1577 mode_final == CURSOR_NONE ? cursor_none :
1578 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1580 SDLSetMouseCursor(cursor_new);
1582 gfx.cursor_mode = mode;
1583 gfx.cursor_mode_final = mode_final;
1586 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1588 // mouse events do not contain logical screen size corrections yet
1589 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1591 mouse_x -= video.screen_xoffset;
1592 mouse_y -= video.screen_yoffset;
1594 gfx.mouse_x = mouse_x;
1595 gfx.mouse_y = mouse_y;
1598 void UpdateMousePosition(void)
1600 int mouse_x, mouse_y;
1603 SDL_GetMouseState(&mouse_x, &mouse_y);
1605 UpdateRawMousePosition(mouse_x, mouse_y);
1609 // ============================================================================
1611 // ============================================================================
1613 void OpenAudio(void)
1615 // always start with reliable default values
1616 audio.sound_available = FALSE;
1617 audio.music_available = FALSE;
1618 audio.loops_available = FALSE;
1620 audio.sound_enabled = FALSE;
1621 audio.sound_deactivated = FALSE;
1623 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1624 audio.mixer_pid = 0;
1625 audio.device_name = NULL;
1626 audio.device_fd = -1;
1628 audio.num_channels = 0;
1629 audio.music_channel = 0;
1630 audio.first_sound_channel = 0;
1635 void CloseAudio(void)
1639 audio.sound_enabled = FALSE;
1642 void SetAudioMode(boolean enabled)
1644 if (!audio.sound_available)
1647 audio.sound_enabled = enabled;
1651 // ============================================================================
1653 // ============================================================================
1655 void InitEventFilter(EventFilter filter_function)
1657 SDL_SetEventFilter(filter_function, NULL);
1660 boolean PendingEvent(void)
1662 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1665 void WaitEvent(Event *event)
1667 SDLWaitEvent(event);
1670 void PeekEvent(Event *event)
1672 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1675 void PumpEvents(void)
1680 void CheckQuitEvent(void)
1682 if (SDL_QuitRequested())
1683 program.exit_function(0);
1686 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1688 // key up/down events in SDL2 do not return text characters anymore
1689 return event->keysym.sym;
1692 KeyMod HandleKeyModState(Key key, int key_status)
1694 static KeyMod current_modifiers = KMOD_None;
1696 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1698 KeyMod new_modifier = KMOD_None;
1703 new_modifier = KMOD_Shift_L;
1706 new_modifier = KMOD_Shift_R;
1708 case KSYM_Control_L:
1709 new_modifier = KMOD_Control_L;
1711 case KSYM_Control_R:
1712 new_modifier = KMOD_Control_R;
1715 new_modifier = KMOD_Meta_L;
1718 new_modifier = KMOD_Meta_R;
1721 new_modifier = KMOD_Alt_L;
1724 new_modifier = KMOD_Alt_R;
1730 if (key_status == KEY_PRESSED)
1731 current_modifiers |= new_modifier;
1733 current_modifiers &= ~new_modifier;
1736 return current_modifiers;
1739 KeyMod GetKeyModState(void)
1741 return (KeyMod)SDL_GetModState();
1744 KeyMod GetKeyModStateFromEvents(void)
1746 /* always use key modifier state as tracked from key events (this is needed
1747 if the modifier key event was injected into the event queue, but the key
1748 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1749 query the keys as held pressed on the keyboard) -- this case is currently
1750 only used to filter out clipboard insert events from "True X-Mouse" tool */
1752 return HandleKeyModState(KSYM_UNDEFINED, 0);
1755 void StartTextInput(int x, int y, int width, int height)
1757 textinput_status = TRUE;
1759 #if defined(HAS_SCREEN_KEYBOARD)
1760 SDL_StartTextInput();
1762 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1764 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1765 video.shifted_up_delay = SDL_GetTicks();
1766 video.shifted_up = TRUE;
1771 void StopTextInput(void)
1773 textinput_status = FALSE;
1775 #if defined(HAS_SCREEN_KEYBOARD)
1776 SDL_StopTextInput();
1778 if (video.shifted_up)
1780 video.shifted_up_pos = 0;
1781 video.shifted_up_delay = SDL_GetTicks();
1782 video.shifted_up = FALSE;
1787 void PushUserEvent(int code, int value1, int value2)
1791 SDL_memset(&event, 0, sizeof(event));
1793 event.type = EVENT_USER;
1795 event.value1 = value1;
1796 event.value2 = value2;
1798 SDL_PushEvent((SDL_Event *)&event);
1802 // ============================================================================
1803 // joystick functions
1804 // ============================================================================
1806 void InitJoysticks(void)
1810 #if defined(NO_JOYSTICK)
1811 return; // joysticks generally deactivated by compile-time directive
1814 // always start with reliable default values
1815 joystick.status = JOYSTICK_NOT_AVAILABLE;
1816 for (i = 0; i < MAX_PLAYERS; i++)
1817 joystick.nr[i] = -1; // no joystick configured
1822 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1824 return SDLReadJoystick(nr, x, y, b1, b2);
1827 boolean CheckJoystickOpened(int nr)
1829 return SDLCheckJoystickOpened(nr);
1832 void ClearJoystickState(void)
1834 SDLClearJoystickState();