1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 // ============================================================================
29 // ============================================================================
31 struct ProgramInfo program;
32 struct NetworkInfo network;
33 struct 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;
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 InitRuntimeInfo()
120 runtime.uses_touch_device = FALSE;
123 void InitScoresInfo(void)
125 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
127 program.global_scores = directoryExists(global_scores_dir);
128 program.many_scores_per_name = !program.global_scores;
133 if (program.global_scores)
135 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
137 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
138 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
142 Error(ERR_DEBUG, "Using private, single-user scores directory.");
147 free(global_scores_dir);
150 void SetWindowTitle(void)
152 program.window_title = program.window_title_function();
157 void InitWindowTitleFunction(char *(*window_title_function)(void))
159 program.window_title_function = window_title_function;
162 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
164 program.exit_message_function = exit_message_function;
167 void InitExitFunction(void (*exit_function)(int))
169 program.exit_function = exit_function;
171 // set signal handlers to custom exit function
172 // signal(SIGINT, exit_function);
173 signal(SIGTERM, exit_function);
175 // set exit function to automatically cleanup SDL stuff after exit()
179 void InitPlatformDependentStuff(void)
181 // this is initialized in GetOptions(), but may already be used before
182 options.verbose = TRUE;
186 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
188 if (SDL_Init(sdl_init_flags) < 0)
189 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
194 void ClosePlatformDependentStuff(void)
199 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
200 int real_sx, int real_sy,
201 int full_sxsize, int full_sysize,
202 Bitmap *field_save_buffer)
208 gfx.real_sx = real_sx;
209 gfx.real_sy = real_sy;
210 gfx.full_sxsize = full_sxsize;
211 gfx.full_sysize = full_sysize;
213 gfx.field_save_buffer = field_save_buffer;
215 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
216 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
219 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
221 gfx.game_tile_size = game_tile_size;
222 gfx.standard_tile_size = standard_tile_size;
225 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
233 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
241 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
249 void InitGfxWindowInfo(int win_xsize, int win_ysize)
251 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
253 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
255 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
257 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
258 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
259 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
260 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
262 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
265 gfx.win_xsize = win_xsize;
266 gfx.win_ysize = win_ysize;
268 gfx.background_bitmap_mask = REDRAW_NONE;
271 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
273 // currently only used by MSDOS code to alloc VRAM buffer, if available
274 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
275 gfx.scrollbuffer_width = scrollbuffer_width;
276 gfx.scrollbuffer_height = scrollbuffer_height;
279 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
281 gfx.clipping_enabled = enabled;
284 gfx.clip_width = width;
285 gfx.clip_height = height;
288 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
290 gfx.draw_busy_anim_function = draw_busy_anim_function;
293 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
295 gfx.draw_global_anim_function = draw_global_anim_function;
298 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
300 gfx.draw_global_border_function = draw_global_border_function;
303 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
305 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
308 void InitGfxCustomArtworkInfo(void)
310 gfx.override_level_graphics = FALSE;
311 gfx.override_level_sounds = FALSE;
312 gfx.override_level_music = FALSE;
314 gfx.draw_init_text = TRUE;
317 void InitGfxOtherSettings(void)
319 gfx.cursor_mode = CURSOR_DEFAULT;
320 gfx.cursor_mode_override = CURSOR_UNDEFINED;
321 gfx.cursor_mode_final = gfx.cursor_mode;
327 void InitTileCursorInfo(void)
329 tile_cursor.enabled = FALSE;
330 tile_cursor.active = FALSE;
331 tile_cursor.moving = FALSE;
333 tile_cursor.xpos = 0;
334 tile_cursor.ypos = 0;
337 tile_cursor.target_x = 0;
338 tile_cursor.target_y = 0;
344 void InitOverlayInfo(void)
346 int nr = GRID_ACTIVE_NR();
349 overlay.enabled = FALSE;
350 overlay.active = FALSE;
352 overlay.show_grid = FALSE;
354 overlay.grid_xsize = setup.touch.grid_xsize[nr];
355 overlay.grid_ysize = setup.touch.grid_ysize[nr];
357 for (x = 0; x < MAX_GRID_XSIZE; x++)
358 for (y = 0; y < MAX_GRID_YSIZE; y++)
359 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
361 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
362 overlay.grid_button_action = JOY_NO_ACTION;
364 #if defined(USE_TOUCH_INPUT_OVERLAY)
365 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
366 overlay.enabled = TRUE;
370 void SetTileCursorEnabled(boolean enabled)
372 tile_cursor.enabled = enabled;
375 void SetTileCursorActive(boolean active)
377 tile_cursor.active = active;
380 void SetTileCursorTargetXY(int x, int y)
382 // delayed placement of tile selection cursor at target position
383 // (tile cursor will be moved to target position step by step)
385 tile_cursor.xpos = x;
386 tile_cursor.ypos = y;
387 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
388 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
390 tile_cursor.moving = TRUE;
393 void SetTileCursorXY(int x, int y)
395 // immediate placement of tile selection cursor at target position
397 SetTileCursorTargetXY(x, y);
399 tile_cursor.x = tile_cursor.target_x;
400 tile_cursor.y = tile_cursor.target_y;
402 tile_cursor.moving = FALSE;
405 void SetTileCursorSXSY(int sx, int sy)
411 void SetOverlayEnabled(boolean enabled)
413 overlay.enabled = enabled;
416 void SetOverlayActive(boolean active)
418 overlay.active = active;
421 void SetOverlayShowGrid(boolean show_grid)
423 overlay.show_grid = show_grid;
425 SetOverlayActive(show_grid);
428 SetOverlayEnabled(TRUE);
431 boolean GetOverlayEnabled(void)
433 return overlay.enabled;
436 boolean GetOverlayActive(void)
438 return overlay.active;
441 void SetDrawDeactivationMask(int draw_deactivation_mask)
443 gfx.draw_deactivation_mask = draw_deactivation_mask;
446 int GetDrawDeactivationMask(void)
448 return gfx.draw_deactivation_mask;
451 void SetDrawBackgroundMask(int draw_background_mask)
453 gfx.draw_background_mask = draw_background_mask;
456 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
458 if (background_bitmap_tile != NULL)
459 gfx.background_bitmap_mask |= mask;
461 gfx.background_bitmap_mask &= ~mask;
463 if (background_bitmap_tile == NULL) // empty background requested
466 if (mask == REDRAW_ALL)
467 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
468 0, 0, video.width, video.height);
469 else if (mask == REDRAW_FIELD)
470 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
471 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
472 else if (mask == REDRAW_DOOR_1)
473 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
474 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
477 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
479 // remove every mask before setting mask for window
480 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
481 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
482 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
485 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
487 // remove window area mask before setting mask for main area
488 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
489 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
490 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
493 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
495 // remove window area mask before setting mask for door area
496 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
497 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
498 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
502 // ============================================================================
504 // ============================================================================
506 static int GetRealDepth(int depth)
508 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
511 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
512 int width, int height, Pixel color)
514 SDLFillRectangle(bitmap, x, y, width, height, color);
516 if (bitmap == backbuffer)
517 SetRedrawMaskFromArea(x, y, width, height);
520 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
521 int src_x, int src_y, int width, int height,
522 int dst_x, int dst_y, int mask_mode)
524 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
525 dst_x, dst_y, mask_mode);
527 if (dst_bitmap == backbuffer)
528 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
531 void LimitScreenUpdates(boolean enable)
533 SDLLimitScreenUpdates(enable);
536 void InitVideoDefaults(void)
538 video.default_depth = 32;
541 void InitVideoDisplay(void)
543 if (program.headless)
546 SDLInitVideoDisplay();
550 void CloseVideoDisplay(void)
552 KeyboardAutoRepeatOn();
554 SDL_QuitSubSystem(SDL_INIT_VIDEO);
557 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
560 video.height = height;
561 video.depth = GetRealDepth(depth);
563 video.screen_width = width;
564 video.screen_height = height;
565 video.screen_xoffset = 0;
566 video.screen_yoffset = 0;
568 video.fullscreen_available = FULLSCREEN_STATUS;
569 video.fullscreen_enabled = FALSE;
571 video.window_scaling_available = WINDOW_SCALING_STATUS;
573 video.frame_counter = 0;
574 video.frame_delay = 0;
575 video.frame_delay_value = GAME_FRAME_DELAY;
577 video.shifted_up = FALSE;
578 video.shifted_up_pos = 0;
579 video.shifted_up_pos_last = 0;
580 video.shifted_up_delay = 0;
581 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
583 SDLInitVideoBuffer(fullscreen);
585 video.initialized = !program.headless;
590 static void FreeBitmapPointers(Bitmap *bitmap)
595 SDLFreeBitmapPointers(bitmap);
597 checked_free(bitmap->source_filename);
598 bitmap->source_filename = NULL;
601 static void TransferBitmapPointers(Bitmap *src_bitmap,
604 if (src_bitmap == NULL || dst_bitmap == NULL)
607 FreeBitmapPointers(dst_bitmap);
609 *dst_bitmap = *src_bitmap;
612 void FreeBitmap(Bitmap *bitmap)
617 FreeBitmapPointers(bitmap);
622 Bitmap *CreateBitmapStruct(void)
624 return checked_calloc(sizeof(Bitmap));
627 Bitmap *CreateBitmap(int width, int height, int depth)
629 Bitmap *new_bitmap = CreateBitmapStruct();
630 int real_width = MAX(1, width); // prevent zero bitmap width
631 int real_height = MAX(1, height); // prevent zero bitmap height
632 int real_depth = GetRealDepth(depth);
634 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
636 new_bitmap->width = real_width;
637 new_bitmap->height = real_height;
642 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
646 // if new bitmap size fits into old one, no need to re-create it
647 if (width <= (*bitmap)->width &&
648 height <= (*bitmap)->height)
651 // else adjust size so that old and new bitmap size fit into it
652 width = MAX(width, (*bitmap)->width);
653 height = MAX(height, (*bitmap)->height);
656 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
660 *bitmap = new_bitmap;
664 TransferBitmapPointers(new_bitmap, *bitmap);
670 static void CloseWindow(DrawWindow *window)
675 void SetRedrawMaskFromArea(int x, int y, int width, int height)
679 int x2 = x + width - 1;
680 int y2 = y + height - 1;
682 if (width == 0 || height == 0)
685 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
686 redraw_mask |= REDRAW_FIELD;
687 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
688 redraw_mask |= REDRAW_DOOR_1;
689 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
690 redraw_mask |= REDRAW_DOOR_2;
691 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
692 redraw_mask |= REDRAW_DOOR_3;
694 redraw_mask = REDRAW_ALL;
697 static boolean CheckDrawingArea(int x, int y, int width, int height,
700 if (draw_mask == REDRAW_NONE)
703 if (draw_mask & REDRAW_ALL)
706 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
709 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
712 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
715 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
721 boolean DrawingDeactivatedField(void)
723 if (program.headless)
726 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
732 boolean DrawingDeactivated(int x, int y, int width, int height)
734 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
737 boolean DrawingOnBackground(int x, int y)
739 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
740 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
743 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
744 int *width, int *height, boolean is_dest)
746 int clip_x, clip_y, clip_width, clip_height;
748 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
750 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
751 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
752 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
753 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
759 clip_width = bitmap->width;
760 clip_height = bitmap->height;
763 // skip if rectangle completely outside bitmap
765 if (*x + *width <= clip_x ||
766 *y + *height <= clip_y ||
767 *x >= clip_x + clip_width ||
768 *y >= clip_y + clip_height)
771 // clip if rectangle overlaps bitmap
775 *width -= clip_x - *x;
778 else if (*x + *width > clip_x + clip_width)
780 *width = clip_x + clip_width - *x;
785 *height -= clip_y - *y;
788 else if (*y + *height > clip_y + clip_height)
790 *height = clip_y + clip_height - *y;
796 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
797 int src_x, int src_y, int width, int height,
798 int dst_x, int dst_y)
800 int dst_x_unclipped = dst_x;
801 int dst_y_unclipped = dst_y;
803 if (program.headless)
806 if (src_bitmap == NULL || dst_bitmap == NULL)
809 if (DrawingDeactivated(dst_x, dst_y, width, height))
812 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
813 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
816 // source x/y might need adjustment if destination x/y was clipped top/left
817 src_x += dst_x - dst_x_unclipped;
818 src_y += dst_y - dst_y_unclipped;
820 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
821 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
822 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
823 but is already fixed in SVN and should therefore finally be fixed with
824 the next official SDL release, which is probably version 1.2.14.) */
825 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
827 if (src_bitmap == dst_bitmap)
829 // needed when blitting directly to same bitmap -- should not be needed with
830 // recent SDL libraries, but apparently does not work in 1.2.11 directly
832 static Bitmap *tmp_bitmap = NULL;
833 static int tmp_bitmap_xsize = 0;
834 static int tmp_bitmap_ysize = 0;
836 // start with largest static bitmaps for initial bitmap size ...
837 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
839 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
840 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
843 // ... and allow for later re-adjustments due to custom artwork bitmaps
844 if (src_bitmap->width > tmp_bitmap_xsize ||
845 src_bitmap->height > tmp_bitmap_ysize)
847 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
848 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
850 FreeBitmap(tmp_bitmap);
855 if (tmp_bitmap == NULL)
856 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
859 sysCopyArea(src_bitmap, tmp_bitmap,
860 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
861 sysCopyArea(tmp_bitmap, dst_bitmap,
862 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
867 sysCopyArea(src_bitmap, dst_bitmap,
868 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
871 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
872 int src_x, int src_y, int src_width, int src_height,
873 int dst_x, int dst_y, int dst_width, int dst_height)
875 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
876 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
877 int dst_xsize = dst_width;
878 int dst_ysize = dst_height;
879 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
880 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
883 for (y = 0; y < src_ysteps; y++)
885 for (x = 0; x < src_xsteps; x++)
887 int draw_x = dst_x + x * src_xsize;
888 int draw_y = dst_y + y * src_ysize;
889 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
890 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
892 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
898 void FadeRectangle(int x, int y, int width, int height,
899 int fade_mode, int fade_delay, int post_delay,
900 void (*draw_border_function)(void))
902 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
903 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
906 SDLFadeRectangle(x, y, width, height,
907 fade_mode, fade_delay, post_delay, draw_border_function);
910 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
913 if (DrawingDeactivated(x, y, width, height))
916 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
919 sysFillRectangle(bitmap, x, y, width, height, color);
922 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
924 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
927 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
928 int width, int height)
930 if (DrawingOnBackground(x, y))
931 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
933 ClearRectangle(bitmap, x, y, width, height);
936 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
937 int src_x, int src_y, int width, int height,
938 int dst_x, int dst_y)
940 if (DrawingDeactivated(dst_x, dst_y, width, height))
943 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
944 dst_x, dst_y, BLIT_MASKED);
947 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
948 int src_x, int src_y, int width, int height,
949 int dst_x, int dst_y)
951 if (DrawingOnBackground(dst_x, dst_y))
954 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
958 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
962 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
966 void BlitTexture(Bitmap *bitmap,
967 int src_x, int src_y, int width, int height,
968 int dst_x, int dst_y)
973 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
977 void BlitTextureMasked(Bitmap *bitmap,
978 int src_x, int src_y, int width, int height,
979 int dst_x, int dst_y)
984 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
988 void BlitToScreen(Bitmap *bitmap,
989 int src_x, int src_y, int width, int height,
990 int dst_x, int dst_y)
995 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
996 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
997 width, height, dst_x, dst_y);
999 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1002 void BlitToScreenMasked(Bitmap *bitmap,
1003 int src_x, int src_y, int width, int height,
1004 int dst_x, int dst_y)
1009 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1010 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1011 width, height, dst_x, dst_y);
1013 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1016 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1019 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1022 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1025 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1028 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1029 int to_x, int to_y, Pixel pixel, int line_width)
1033 if (program.headless)
1036 for (x = 0; x < line_width; x++)
1038 for (y = 0; y < line_width; y++)
1040 int dx = x - line_width / 2;
1041 int dy = y - line_width / 2;
1043 if ((x == 0 && y == 0) ||
1044 (x == 0 && y == line_width - 1) ||
1045 (x == line_width - 1 && y == 0) ||
1046 (x == line_width - 1 && y == line_width - 1))
1050 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1055 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1060 for (i = 0; i < num_points - 1; i++)
1061 DrawLine(bitmap, points[i].x, points[i].y,
1062 points[i + 1].x, points[i + 1].y, pixel, line_width);
1065 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1069 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1071 if (program.headless)
1074 if (x < 0 || x >= bitmap->width ||
1075 y < 0 || y >= bitmap->height)
1078 return SDLGetPixel(bitmap, x, y);
1081 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1082 unsigned int color_g, unsigned int color_b)
1084 if (program.headless)
1087 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1090 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1092 unsigned int color_r = (color >> 16) & 0xff;
1093 unsigned int color_g = (color >> 8) & 0xff;
1094 unsigned int color_b = (color >> 0) & 0xff;
1096 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1099 void KeyboardAutoRepeatOn(void)
1101 keyrepeat_status = TRUE;
1104 void KeyboardAutoRepeatOff(void)
1106 keyrepeat_status = FALSE;
1109 boolean SetVideoMode(boolean fullscreen)
1111 return SDLSetVideoMode(fullscreen);
1114 void SetVideoFrameDelay(unsigned int frame_delay_value)
1116 video.frame_delay_value = frame_delay_value;
1119 unsigned int GetVideoFrameDelay(void)
1121 return video.frame_delay_value;
1124 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1126 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1127 (!fullscreen && video.fullscreen_enabled))
1128 fullscreen = SetVideoMode(fullscreen);
1133 Bitmap *LoadImage(char *filename)
1137 new_bitmap = SDLLoadImage(filename);
1140 new_bitmap->source_filename = getStringCopy(filename);
1145 Bitmap *LoadCustomImage(char *basename)
1147 char *filename = getCustomImageFilename(basename);
1150 if (filename == NULL)
1151 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1153 if ((new_bitmap = LoadImage(filename)) == NULL)
1154 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1159 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1161 char *filename = getCustomImageFilename(basename);
1164 if (filename == NULL) // (should never happen)
1166 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1170 if (strEqual(filename, bitmap->source_filename))
1172 // The old and new image are the same (have the same filename and path).
1173 // This usually means that this image does not exist in this graphic set
1174 // and a fallback to the existing image is done.
1179 if ((new_bitmap = LoadImage(filename)) == NULL)
1181 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1185 if (bitmap->width != new_bitmap->width ||
1186 bitmap->height != new_bitmap->height)
1188 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1190 FreeBitmap(new_bitmap);
1194 TransferBitmapPointers(new_bitmap, bitmap);
1198 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1200 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1203 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1205 if (bitmaps[IMG_BITMAP_CUSTOM])
1207 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1209 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1212 if (gfx.game_tile_size == gfx.standard_tile_size)
1214 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1219 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1220 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1221 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1223 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1225 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1226 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1229 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1230 int tile_size, boolean create_small_bitmaps)
1232 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1233 Bitmap *tmp_bitmap_final = NULL;
1234 Bitmap *tmp_bitmap_0 = NULL;
1235 Bitmap *tmp_bitmap_1 = NULL;
1236 Bitmap *tmp_bitmap_2 = NULL;
1237 Bitmap *tmp_bitmap_4 = NULL;
1238 Bitmap *tmp_bitmap_8 = NULL;
1239 Bitmap *tmp_bitmap_16 = NULL;
1240 Bitmap *tmp_bitmap_32 = NULL;
1241 int width_final, height_final;
1242 int width_0, height_0;
1243 int width_1, height_1;
1244 int width_2, height_2;
1245 int width_4, height_4;
1246 int width_8, height_8;
1247 int width_16, height_16;
1248 int width_32, height_32;
1249 int old_width, old_height;
1252 print_timestamp_init("CreateScaledBitmaps");
1254 old_width = old_bitmap->width;
1255 old_height = old_bitmap->height;
1257 // calculate new image dimensions for final image size
1258 width_final = old_width * zoom_factor;
1259 height_final = old_height * zoom_factor;
1261 // get image with final size (this might require scaling up)
1262 // ("final" size may result in non-standard tile size image)
1263 if (zoom_factor != 1)
1264 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1266 tmp_bitmap_final = old_bitmap;
1268 UPDATE_BUSY_STATE();
1270 width_0 = width_1 = width_final;
1271 height_0 = height_1 = height_final;
1273 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1275 if (create_small_bitmaps)
1277 // check if we have a non-gameplay tile size image
1278 if (tile_size != gfx.game_tile_size)
1280 // get image with gameplay tile size
1281 width_0 = width_final * gfx.game_tile_size / tile_size;
1282 height_0 = height_final * gfx.game_tile_size / tile_size;
1284 if (width_0 == old_width)
1285 tmp_bitmap_0 = old_bitmap;
1286 else if (width_0 == width_final)
1287 tmp_bitmap_0 = tmp_bitmap_final;
1289 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1291 UPDATE_BUSY_STATE();
1294 // check if we have a non-standard tile size image
1295 if (tile_size != gfx.standard_tile_size)
1297 // get image with standard tile size
1298 width_1 = width_final * gfx.standard_tile_size / tile_size;
1299 height_1 = height_final * gfx.standard_tile_size / tile_size;
1301 if (width_1 == old_width)
1302 tmp_bitmap_1 = old_bitmap;
1303 else if (width_1 == width_final)
1304 tmp_bitmap_1 = tmp_bitmap_final;
1305 else if (width_1 == width_0)
1306 tmp_bitmap_1 = tmp_bitmap_0;
1308 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1310 UPDATE_BUSY_STATE();
1313 // calculate new image dimensions for small images
1314 width_2 = width_1 / 2;
1315 height_2 = height_1 / 2;
1316 width_4 = width_1 / 4;
1317 height_4 = height_1 / 4;
1318 width_8 = width_1 / 8;
1319 height_8 = height_1 / 8;
1320 width_16 = width_1 / 16;
1321 height_16 = height_1 / 16;
1322 width_32 = width_1 / 32;
1323 height_32 = height_1 / 32;
1325 // get image with 1/2 of normal size (for use in the level editor)
1326 if (width_2 == old_width)
1327 tmp_bitmap_2 = old_bitmap;
1329 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1331 UPDATE_BUSY_STATE();
1333 // get image with 1/4 of normal size (for use in the level editor)
1334 if (width_4 == old_width)
1335 tmp_bitmap_4 = old_bitmap;
1337 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1339 UPDATE_BUSY_STATE();
1341 // get image with 1/8 of normal size (for use on the preview screen)
1342 if (width_8 == old_width)
1343 tmp_bitmap_8 = old_bitmap;
1345 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1347 UPDATE_BUSY_STATE();
1349 // get image with 1/16 of normal size (for use on the preview screen)
1350 if (width_16 == old_width)
1351 tmp_bitmap_16 = old_bitmap;
1353 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1355 UPDATE_BUSY_STATE();
1357 // get image with 1/32 of normal size (for use on the preview screen)
1358 if (width_32 == old_width)
1359 tmp_bitmap_32 = old_bitmap;
1361 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1363 UPDATE_BUSY_STATE();
1365 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1366 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1367 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1368 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1369 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1370 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1372 if (width_0 != width_1)
1373 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1375 if (bitmaps[IMG_BITMAP_CUSTOM])
1376 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1378 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1380 boolean free_old_bitmap = TRUE;
1382 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1383 if (bitmaps[i] == old_bitmap)
1384 free_old_bitmap = FALSE;
1386 if (free_old_bitmap)
1388 // copy image filename from old to new standard sized bitmap
1389 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1390 getStringCopy(old_bitmap->source_filename);
1392 FreeBitmap(old_bitmap);
1397 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1400 UPDATE_BUSY_STATE();
1402 print_timestamp_done("CreateScaledBitmaps");
1405 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1408 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1411 void CreateBitmapTextures(Bitmap **bitmaps)
1413 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1416 void FreeBitmapTextures(Bitmap **bitmaps)
1418 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1421 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1423 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1427 // ----------------------------------------------------------------------------
1428 // mouse pointer functions
1429 // ----------------------------------------------------------------------------
1431 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1433 // XPM image definitions
1434 static const char *cursor_image_none[] =
1436 // width height num_colors chars_per_pixel
1466 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1467 static const char *cursor_image_dot[] =
1469 // width height num_colors chars_per_pixel
1498 static const char **cursor_image_playfield = cursor_image_dot;
1500 // some people complained about a "white dot" on the screen and thought it
1501 // was a graphical error... OK, let's just remove the whole pointer :-)
1502 static const char **cursor_image_playfield = cursor_image_none;
1505 static const int cursor_bit_order = BIT_ORDER_MSB;
1507 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1509 struct MouseCursorInfo *cursor;
1510 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1511 int header_lines = 4;
1514 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1516 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1519 for (y = 0; y < cursor->width; y++)
1521 for (x = 0; x < cursor->height; x++)
1524 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1529 cursor->data[i] = cursor->mask[i] = 0;
1532 switch (image[header_lines + y][x])
1535 cursor->data[i] |= bit_mask;
1536 cursor->mask[i] |= bit_mask;
1540 cursor->mask[i] |= bit_mask;
1549 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1554 void SetMouseCursor(int mode)
1556 static struct MouseCursorInfo *cursor_none = NULL;
1557 static struct MouseCursorInfo *cursor_playfield = NULL;
1558 struct MouseCursorInfo *cursor_new;
1559 int mode_final = mode;
1561 if (cursor_none == NULL)
1562 cursor_none = get_cursor_from_image(cursor_image_none);
1564 if (cursor_playfield == NULL)
1565 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1567 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1568 mode_final = gfx.cursor_mode_override;
1570 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1571 mode_final == CURSOR_NONE ? cursor_none :
1572 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1574 SDLSetMouseCursor(cursor_new);
1576 gfx.cursor_mode = mode;
1577 gfx.cursor_mode_final = mode_final;
1580 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1582 // mouse events do not contain logical screen size corrections yet
1583 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1585 mouse_x -= video.screen_xoffset;
1586 mouse_y -= video.screen_yoffset;
1588 gfx.mouse_x = mouse_x;
1589 gfx.mouse_y = mouse_y;
1592 void UpdateMousePosition(void)
1594 int mouse_x, mouse_y;
1597 SDL_GetMouseState(&mouse_x, &mouse_y);
1599 UpdateRawMousePosition(mouse_x, mouse_y);
1603 // ============================================================================
1605 // ============================================================================
1607 void OpenAudio(void)
1609 // always start with reliable default values
1610 audio.sound_available = FALSE;
1611 audio.music_available = FALSE;
1612 audio.loops_available = FALSE;
1614 audio.sound_enabled = FALSE;
1615 audio.sound_deactivated = FALSE;
1617 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1618 audio.mixer_pid = 0;
1619 audio.device_name = NULL;
1620 audio.device_fd = -1;
1622 audio.num_channels = 0;
1623 audio.music_channel = 0;
1624 audio.first_sound_channel = 0;
1629 void CloseAudio(void)
1633 audio.sound_enabled = FALSE;
1636 void SetAudioMode(boolean enabled)
1638 if (!audio.sound_available)
1641 audio.sound_enabled = enabled;
1645 // ============================================================================
1647 // ============================================================================
1649 void InitEventFilter(EventFilter filter_function)
1651 SDL_SetEventFilter(filter_function, NULL);
1654 boolean PendingEvent(void)
1656 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1659 void WaitEvent(Event *event)
1661 SDLWaitEvent(event);
1664 void PeekEvent(Event *event)
1666 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1669 void PumpEvents(void)
1674 void CheckQuitEvent(void)
1676 if (SDL_QuitRequested())
1677 program.exit_function(0);
1680 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1682 // key up/down events in SDL2 do not return text characters anymore
1683 return event->keysym.sym;
1686 KeyMod HandleKeyModState(Key key, int key_status)
1688 static KeyMod current_modifiers = KMOD_None;
1690 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1692 KeyMod new_modifier = KMOD_None;
1697 new_modifier = KMOD_Shift_L;
1700 new_modifier = KMOD_Shift_R;
1702 case KSYM_Control_L:
1703 new_modifier = KMOD_Control_L;
1705 case KSYM_Control_R:
1706 new_modifier = KMOD_Control_R;
1709 new_modifier = KMOD_Meta_L;
1712 new_modifier = KMOD_Meta_R;
1715 new_modifier = KMOD_Alt_L;
1718 new_modifier = KMOD_Alt_R;
1724 if (key_status == KEY_PRESSED)
1725 current_modifiers |= new_modifier;
1727 current_modifiers &= ~new_modifier;
1730 return current_modifiers;
1733 KeyMod GetKeyModState(void)
1735 return (KeyMod)SDL_GetModState();
1738 KeyMod GetKeyModStateFromEvents(void)
1740 /* always use key modifier state as tracked from key events (this is needed
1741 if the modifier key event was injected into the event queue, but the key
1742 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1743 query the keys as held pressed on the keyboard) -- this case is currently
1744 only used to filter out clipboard insert events from "True X-Mouse" tool */
1746 return HandleKeyModState(KSYM_UNDEFINED, 0);
1749 void StartTextInput(int x, int y, int width, int height)
1751 #if defined(HAS_SCREEN_KEYBOARD)
1752 SDL_StartTextInput();
1754 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1756 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1757 video.shifted_up_delay = SDL_GetTicks();
1758 video.shifted_up = TRUE;
1763 void StopTextInput(void)
1765 #if defined(HAS_SCREEN_KEYBOARD)
1766 SDL_StopTextInput();
1768 if (video.shifted_up)
1770 video.shifted_up_pos = 0;
1771 video.shifted_up_delay = SDL_GetTicks();
1772 video.shifted_up = FALSE;
1777 void PushUserEvent(int code, int value1, int value2)
1781 SDL_memset(&event, 0, sizeof(event));
1783 event.type = EVENT_USER;
1785 event.value1 = value1;
1786 event.value2 = value2;
1788 SDL_PushEvent((SDL_Event *)&event);
1792 // ============================================================================
1793 // joystick functions
1794 // ============================================================================
1796 void InitJoysticks(void)
1800 #if defined(NO_JOYSTICK)
1801 return; // joysticks generally deactivated by compile-time directive
1804 // always start with reliable default values
1805 joystick.status = JOYSTICK_NOT_AVAILABLE;
1806 for (i = 0; i < MAX_PLAYERS; i++)
1807 joystick.nr[i] = -1; // no joystick configured
1812 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1814 return SDLReadJoystick(nr, x, y, b1, b2);
1817 boolean CheckJoystickOpened(int nr)
1819 return SDLCheckJoystickOpened(nr);
1822 void ClearJoystickState(void)
1824 SDLClearJoystickState();