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;
323 // prevent initially displaying custom mouse cursor in upper left corner
324 gfx.mouse_x = POS_OFFSCREEN;
325 gfx.mouse_y = POS_OFFSCREEN;
328 void InitTileCursorInfo(void)
330 tile_cursor.enabled = FALSE;
331 tile_cursor.active = FALSE;
332 tile_cursor.moving = FALSE;
334 tile_cursor.xpos = 0;
335 tile_cursor.ypos = 0;
338 tile_cursor.target_x = 0;
339 tile_cursor.target_y = 0;
345 void InitOverlayInfo(void)
347 int nr = GRID_ACTIVE_NR();
350 overlay.enabled = FALSE;
351 overlay.active = FALSE;
353 overlay.show_grid = FALSE;
355 overlay.grid_xsize = setup.touch.grid_xsize[nr];
356 overlay.grid_ysize = setup.touch.grid_ysize[nr];
358 for (x = 0; x < MAX_GRID_XSIZE; x++)
359 for (y = 0; y < MAX_GRID_YSIZE; y++)
360 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
362 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
363 overlay.grid_button_action = JOY_NO_ACTION;
365 #if defined(USE_TOUCH_INPUT_OVERLAY)
366 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
367 overlay.enabled = TRUE;
371 void SetTileCursorEnabled(boolean enabled)
373 tile_cursor.enabled = enabled;
376 void SetTileCursorActive(boolean active)
378 tile_cursor.active = active;
381 void SetTileCursorTargetXY(int x, int y)
383 // delayed placement of tile selection cursor at target position
384 // (tile cursor will be moved to target position step by step)
386 tile_cursor.xpos = x;
387 tile_cursor.ypos = y;
388 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
389 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
391 tile_cursor.moving = TRUE;
394 void SetTileCursorXY(int x, int y)
396 // immediate placement of tile selection cursor at target position
398 SetTileCursorTargetXY(x, y);
400 tile_cursor.x = tile_cursor.target_x;
401 tile_cursor.y = tile_cursor.target_y;
403 tile_cursor.moving = FALSE;
406 void SetTileCursorSXSY(int sx, int sy)
412 void SetOverlayEnabled(boolean enabled)
414 overlay.enabled = enabled;
417 void SetOverlayActive(boolean active)
419 overlay.active = active;
422 void SetOverlayShowGrid(boolean show_grid)
424 overlay.show_grid = show_grid;
426 SetOverlayActive(show_grid);
429 SetOverlayEnabled(TRUE);
432 boolean GetOverlayEnabled(void)
434 return overlay.enabled;
437 boolean GetOverlayActive(void)
439 return overlay.active;
442 void SetDrawDeactivationMask(int draw_deactivation_mask)
444 gfx.draw_deactivation_mask = draw_deactivation_mask;
447 int GetDrawDeactivationMask(void)
449 return gfx.draw_deactivation_mask;
452 void SetDrawBackgroundMask(int draw_background_mask)
454 gfx.draw_background_mask = draw_background_mask;
457 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
459 if (background_bitmap_tile != NULL)
460 gfx.background_bitmap_mask |= mask;
462 gfx.background_bitmap_mask &= ~mask;
464 if (background_bitmap_tile == NULL) // empty background requested
467 if (mask == REDRAW_ALL)
468 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
469 0, 0, video.width, video.height);
470 else if (mask == REDRAW_FIELD)
471 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
472 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
473 else if (mask == REDRAW_DOOR_1)
474 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
475 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
478 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
480 // remove every mask before setting mask for window
481 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
482 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
483 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
486 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
488 // remove window area mask before setting mask for main area
489 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
490 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
491 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
494 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
496 // remove window area mask before setting mask for door area
497 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
498 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
499 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
503 // ============================================================================
505 // ============================================================================
507 static int GetRealDepth(int depth)
509 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
512 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
513 int width, int height, Pixel color)
515 SDLFillRectangle(bitmap, x, y, width, height, color);
517 if (bitmap == backbuffer)
518 SetRedrawMaskFromArea(x, y, width, height);
521 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
522 int src_x, int src_y, int width, int height,
523 int dst_x, int dst_y, int mask_mode)
525 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
526 dst_x, dst_y, mask_mode);
528 if (dst_bitmap == backbuffer)
529 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
532 void LimitScreenUpdates(boolean enable)
534 SDLLimitScreenUpdates(enable);
537 void InitVideoDefaults(void)
539 video.default_depth = 32;
542 void InitVideoDisplay(void)
544 if (program.headless)
547 SDLInitVideoDisplay();
551 void CloseVideoDisplay(void)
553 KeyboardAutoRepeatOn();
555 SDL_QuitSubSystem(SDL_INIT_VIDEO);
558 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
561 video.height = height;
562 video.depth = GetRealDepth(depth);
564 video.screen_width = width;
565 video.screen_height = height;
566 video.screen_xoffset = 0;
567 video.screen_yoffset = 0;
569 video.fullscreen_available = FULLSCREEN_STATUS;
570 video.fullscreen_enabled = FALSE;
572 video.window_scaling_available = WINDOW_SCALING_STATUS;
574 video.frame_counter = 0;
575 video.frame_delay = 0;
576 video.frame_delay_value = GAME_FRAME_DELAY;
578 video.shifted_up = FALSE;
579 video.shifted_up_pos = 0;
580 video.shifted_up_pos_last = 0;
581 video.shifted_up_delay = 0;
582 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
584 SDLInitVideoBuffer(fullscreen);
586 video.initialized = !program.headless;
591 static void FreeBitmapPointers(Bitmap *bitmap)
596 SDLFreeBitmapPointers(bitmap);
598 checked_free(bitmap->source_filename);
599 bitmap->source_filename = NULL;
602 static void TransferBitmapPointers(Bitmap *src_bitmap,
605 if (src_bitmap == NULL || dst_bitmap == NULL)
608 FreeBitmapPointers(dst_bitmap);
610 *dst_bitmap = *src_bitmap;
613 void FreeBitmap(Bitmap *bitmap)
618 FreeBitmapPointers(bitmap);
623 Bitmap *CreateBitmapStruct(void)
625 return checked_calloc(sizeof(Bitmap));
628 Bitmap *CreateBitmap(int width, int height, int depth)
630 Bitmap *new_bitmap = CreateBitmapStruct();
631 int real_width = MAX(1, width); // prevent zero bitmap width
632 int real_height = MAX(1, height); // prevent zero bitmap height
633 int real_depth = GetRealDepth(depth);
635 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
637 new_bitmap->width = real_width;
638 new_bitmap->height = real_height;
643 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
647 // if new bitmap size fits into old one, no need to re-create it
648 if (width <= (*bitmap)->width &&
649 height <= (*bitmap)->height)
652 // else adjust size so that old and new bitmap size fit into it
653 width = MAX(width, (*bitmap)->width);
654 height = MAX(height, (*bitmap)->height);
657 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
661 *bitmap = new_bitmap;
665 TransferBitmapPointers(new_bitmap, *bitmap);
671 static void CloseWindow(DrawWindow *window)
676 void SetRedrawMaskFromArea(int x, int y, int width, int height)
680 int x2 = x + width - 1;
681 int y2 = y + height - 1;
683 if (width == 0 || height == 0)
686 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
687 redraw_mask |= REDRAW_FIELD;
688 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
689 redraw_mask |= REDRAW_DOOR_1;
690 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
691 redraw_mask |= REDRAW_DOOR_2;
692 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
693 redraw_mask |= REDRAW_DOOR_3;
695 redraw_mask = REDRAW_ALL;
698 static boolean CheckDrawingArea(int x, int y, int width, int height,
701 if (draw_mask == REDRAW_NONE)
704 if (draw_mask & REDRAW_ALL)
707 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
710 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
713 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
716 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
722 boolean DrawingDeactivatedField(void)
724 if (program.headless)
727 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
733 boolean DrawingDeactivated(int x, int y, int width, int height)
735 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
738 boolean DrawingOnBackground(int x, int y)
740 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
741 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
744 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
745 int *width, int *height, boolean is_dest)
747 int clip_x, clip_y, clip_width, clip_height;
749 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
751 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
752 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
753 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
754 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
760 clip_width = bitmap->width;
761 clip_height = bitmap->height;
764 // skip if rectangle completely outside bitmap
766 if (*x + *width <= clip_x ||
767 *y + *height <= clip_y ||
768 *x >= clip_x + clip_width ||
769 *y >= clip_y + clip_height)
772 // clip if rectangle overlaps bitmap
776 *width -= clip_x - *x;
779 else if (*x + *width > clip_x + clip_width)
781 *width = clip_x + clip_width - *x;
786 *height -= clip_y - *y;
789 else if (*y + *height > clip_y + clip_height)
791 *height = clip_y + clip_height - *y;
797 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
798 int src_x, int src_y, int width, int height,
799 int dst_x, int dst_y)
801 int dst_x_unclipped = dst_x;
802 int dst_y_unclipped = dst_y;
804 if (program.headless)
807 if (src_bitmap == NULL || dst_bitmap == NULL)
810 if (DrawingDeactivated(dst_x, dst_y, width, height))
813 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
814 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
817 // source x/y might need adjustment if destination x/y was clipped top/left
818 src_x += dst_x - dst_x_unclipped;
819 src_y += dst_y - dst_y_unclipped;
821 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
822 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
823 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
824 but is already fixed in SVN and should therefore finally be fixed with
825 the next official SDL release, which is probably version 1.2.14.) */
826 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
828 if (src_bitmap == dst_bitmap)
830 // needed when blitting directly to same bitmap -- should not be needed with
831 // recent SDL libraries, but apparently does not work in 1.2.11 directly
833 static Bitmap *tmp_bitmap = NULL;
834 static int tmp_bitmap_xsize = 0;
835 static int tmp_bitmap_ysize = 0;
837 // start with largest static bitmaps for initial bitmap size ...
838 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
840 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
841 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
844 // ... and allow for later re-adjustments due to custom artwork bitmaps
845 if (src_bitmap->width > tmp_bitmap_xsize ||
846 src_bitmap->height > tmp_bitmap_ysize)
848 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
849 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
851 FreeBitmap(tmp_bitmap);
856 if (tmp_bitmap == NULL)
857 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
860 sysCopyArea(src_bitmap, tmp_bitmap,
861 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
862 sysCopyArea(tmp_bitmap, dst_bitmap,
863 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
868 sysCopyArea(src_bitmap, dst_bitmap,
869 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
872 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
873 int src_x, int src_y, int src_width, int src_height,
874 int dst_x, int dst_y, int dst_width, int dst_height)
876 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
877 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
878 int dst_xsize = dst_width;
879 int dst_ysize = dst_height;
880 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
881 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
884 for (y = 0; y < src_ysteps; y++)
886 for (x = 0; x < src_xsteps; x++)
888 int draw_x = dst_x + x * src_xsize;
889 int draw_y = dst_y + y * src_ysize;
890 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
891 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
893 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
899 void FadeRectangle(int x, int y, int width, int height,
900 int fade_mode, int fade_delay, int post_delay,
901 void (*draw_border_function)(void))
903 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
904 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
907 SDLFadeRectangle(x, y, width, height,
908 fade_mode, fade_delay, post_delay, draw_border_function);
911 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
914 if (DrawingDeactivated(x, y, width, height))
917 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
920 sysFillRectangle(bitmap, x, y, width, height, color);
923 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
925 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
928 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
929 int width, int height)
931 if (DrawingOnBackground(x, y))
932 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
934 ClearRectangle(bitmap, x, y, width, height);
937 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
938 int src_x, int src_y, int width, int height,
939 int dst_x, int dst_y)
941 if (DrawingDeactivated(dst_x, dst_y, width, height))
944 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
945 dst_x, dst_y, BLIT_MASKED);
948 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
949 int src_x, int src_y, int width, int height,
950 int dst_x, int dst_y)
952 if (DrawingOnBackground(dst_x, dst_y))
955 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
959 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
963 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
967 void BlitTexture(Bitmap *bitmap,
968 int src_x, int src_y, int width, int height,
969 int dst_x, int dst_y)
974 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
978 void BlitTextureMasked(Bitmap *bitmap,
979 int src_x, int src_y, int width, int height,
980 int dst_x, int dst_y)
985 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
989 void BlitToScreen(Bitmap *bitmap,
990 int src_x, int src_y, int width, int height,
991 int dst_x, int dst_y)
996 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
997 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
998 width, height, dst_x, dst_y);
1000 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1003 void BlitToScreenMasked(Bitmap *bitmap,
1004 int src_x, int src_y, int width, int height,
1005 int dst_x, int dst_y)
1010 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1011 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1012 width, height, dst_x, dst_y);
1014 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1017 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1020 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1023 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1026 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1029 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1030 int to_x, int to_y, Pixel pixel, int line_width)
1034 if (program.headless)
1037 for (x = 0; x < line_width; x++)
1039 for (y = 0; y < line_width; y++)
1041 int dx = x - line_width / 2;
1042 int dy = y - line_width / 2;
1044 if ((x == 0 && y == 0) ||
1045 (x == 0 && y == line_width - 1) ||
1046 (x == line_width - 1 && y == 0) ||
1047 (x == line_width - 1 && y == line_width - 1))
1051 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1056 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1061 for (i = 0; i < num_points - 1; i++)
1062 DrawLine(bitmap, points[i].x, points[i].y,
1063 points[i + 1].x, points[i + 1].y, pixel, line_width);
1066 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1070 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1072 if (program.headless)
1075 if (x < 0 || x >= bitmap->width ||
1076 y < 0 || y >= bitmap->height)
1079 return SDLGetPixel(bitmap, x, y);
1082 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1083 unsigned int color_g, unsigned int color_b)
1085 if (program.headless)
1088 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1091 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1093 unsigned int color_r = (color >> 16) & 0xff;
1094 unsigned int color_g = (color >> 8) & 0xff;
1095 unsigned int color_b = (color >> 0) & 0xff;
1097 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1100 void KeyboardAutoRepeatOn(void)
1102 keyrepeat_status = TRUE;
1105 void KeyboardAutoRepeatOff(void)
1107 keyrepeat_status = FALSE;
1110 boolean SetVideoMode(boolean fullscreen)
1112 return SDLSetVideoMode(fullscreen);
1115 void SetVideoFrameDelay(unsigned int frame_delay_value)
1117 video.frame_delay_value = frame_delay_value;
1120 unsigned int GetVideoFrameDelay(void)
1122 return video.frame_delay_value;
1125 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1127 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1128 (!fullscreen && video.fullscreen_enabled))
1129 fullscreen = SetVideoMode(fullscreen);
1134 Bitmap *LoadImage(char *filename)
1138 new_bitmap = SDLLoadImage(filename);
1141 new_bitmap->source_filename = getStringCopy(filename);
1146 Bitmap *LoadCustomImage(char *basename)
1148 char *filename = getCustomImageFilename(basename);
1151 if (filename == NULL)
1152 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1154 if ((new_bitmap = LoadImage(filename)) == NULL)
1155 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1160 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1162 char *filename = getCustomImageFilename(basename);
1165 if (filename == NULL) // (should never happen)
1167 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1171 if (strEqual(filename, bitmap->source_filename))
1173 // The old and new image are the same (have the same filename and path).
1174 // This usually means that this image does not exist in this graphic set
1175 // and a fallback to the existing image is done.
1180 if ((new_bitmap = LoadImage(filename)) == NULL)
1182 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1186 if (bitmap->width != new_bitmap->width ||
1187 bitmap->height != new_bitmap->height)
1189 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1191 FreeBitmap(new_bitmap);
1195 TransferBitmapPointers(new_bitmap, bitmap);
1199 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1201 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1204 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1206 if (bitmaps[IMG_BITMAP_CUSTOM])
1208 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1210 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1213 if (gfx.game_tile_size == gfx.standard_tile_size)
1215 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1220 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1221 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1222 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1224 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1226 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1227 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1230 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1231 int tile_size, boolean create_small_bitmaps)
1233 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1234 Bitmap *tmp_bitmap_final = NULL;
1235 Bitmap *tmp_bitmap_0 = NULL;
1236 Bitmap *tmp_bitmap_1 = NULL;
1237 Bitmap *tmp_bitmap_2 = NULL;
1238 Bitmap *tmp_bitmap_4 = NULL;
1239 Bitmap *tmp_bitmap_8 = NULL;
1240 Bitmap *tmp_bitmap_16 = NULL;
1241 Bitmap *tmp_bitmap_32 = NULL;
1242 int width_final, height_final;
1243 int width_0, height_0;
1244 int width_1, height_1;
1245 int width_2, height_2;
1246 int width_4, height_4;
1247 int width_8, height_8;
1248 int width_16, height_16;
1249 int width_32, height_32;
1250 int old_width, old_height;
1253 print_timestamp_init("CreateScaledBitmaps");
1255 old_width = old_bitmap->width;
1256 old_height = old_bitmap->height;
1258 // calculate new image dimensions for final image size
1259 width_final = old_width * zoom_factor;
1260 height_final = old_height * zoom_factor;
1262 // get image with final size (this might require scaling up)
1263 // ("final" size may result in non-standard tile size image)
1264 if (zoom_factor != 1)
1265 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1267 tmp_bitmap_final = old_bitmap;
1269 UPDATE_BUSY_STATE();
1271 width_0 = width_1 = width_final;
1272 height_0 = height_1 = height_final;
1274 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1276 if (create_small_bitmaps)
1278 // check if we have a non-gameplay tile size image
1279 if (tile_size != gfx.game_tile_size)
1281 // get image with gameplay tile size
1282 width_0 = width_final * gfx.game_tile_size / tile_size;
1283 height_0 = height_final * gfx.game_tile_size / tile_size;
1285 if (width_0 == old_width)
1286 tmp_bitmap_0 = old_bitmap;
1287 else if (width_0 == width_final)
1288 tmp_bitmap_0 = tmp_bitmap_final;
1290 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1292 UPDATE_BUSY_STATE();
1295 // check if we have a non-standard tile size image
1296 if (tile_size != gfx.standard_tile_size)
1298 // get image with standard tile size
1299 width_1 = width_final * gfx.standard_tile_size / tile_size;
1300 height_1 = height_final * gfx.standard_tile_size / tile_size;
1302 if (width_1 == old_width)
1303 tmp_bitmap_1 = old_bitmap;
1304 else if (width_1 == width_final)
1305 tmp_bitmap_1 = tmp_bitmap_final;
1306 else if (width_1 == width_0)
1307 tmp_bitmap_1 = tmp_bitmap_0;
1309 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1311 UPDATE_BUSY_STATE();
1314 // calculate new image dimensions for small images
1315 width_2 = width_1 / 2;
1316 height_2 = height_1 / 2;
1317 width_4 = width_1 / 4;
1318 height_4 = height_1 / 4;
1319 width_8 = width_1 / 8;
1320 height_8 = height_1 / 8;
1321 width_16 = width_1 / 16;
1322 height_16 = height_1 / 16;
1323 width_32 = width_1 / 32;
1324 height_32 = height_1 / 32;
1326 // get image with 1/2 of normal size (for use in the level editor)
1327 if (width_2 == old_width)
1328 tmp_bitmap_2 = old_bitmap;
1330 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1332 UPDATE_BUSY_STATE();
1334 // get image with 1/4 of normal size (for use in the level editor)
1335 if (width_4 == old_width)
1336 tmp_bitmap_4 = old_bitmap;
1338 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1340 UPDATE_BUSY_STATE();
1342 // get image with 1/8 of normal size (for use on the preview screen)
1343 if (width_8 == old_width)
1344 tmp_bitmap_8 = old_bitmap;
1346 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1348 UPDATE_BUSY_STATE();
1350 // get image with 1/16 of normal size (for use on the preview screen)
1351 if (width_16 == old_width)
1352 tmp_bitmap_16 = old_bitmap;
1354 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1356 UPDATE_BUSY_STATE();
1358 // get image with 1/32 of normal size (for use on the preview screen)
1359 if (width_32 == old_width)
1360 tmp_bitmap_32 = old_bitmap;
1362 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1364 UPDATE_BUSY_STATE();
1366 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1367 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1368 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1369 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1370 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1371 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1373 if (width_0 != width_1)
1374 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1376 if (bitmaps[IMG_BITMAP_CUSTOM])
1377 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1379 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1381 boolean free_old_bitmap = TRUE;
1383 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1384 if (bitmaps[i] == old_bitmap)
1385 free_old_bitmap = FALSE;
1387 if (free_old_bitmap)
1389 // copy image filename from old to new standard sized bitmap
1390 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1391 getStringCopy(old_bitmap->source_filename);
1393 FreeBitmap(old_bitmap);
1398 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1401 UPDATE_BUSY_STATE();
1403 print_timestamp_done("CreateScaledBitmaps");
1406 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1409 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1412 void CreateBitmapTextures(Bitmap **bitmaps)
1414 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1417 void FreeBitmapTextures(Bitmap **bitmaps)
1419 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1422 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1424 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1428 // ----------------------------------------------------------------------------
1429 // mouse pointer functions
1430 // ----------------------------------------------------------------------------
1432 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1434 // XPM image definitions
1435 static const char *cursor_image_none[] =
1437 // width height num_colors chars_per_pixel
1467 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1468 static const char *cursor_image_dot[] =
1470 // width height num_colors chars_per_pixel
1499 static const char **cursor_image_playfield = cursor_image_dot;
1501 // some people complained about a "white dot" on the screen and thought it
1502 // was a graphical error... OK, let's just remove the whole pointer :-)
1503 static const char **cursor_image_playfield = cursor_image_none;
1506 static const int cursor_bit_order = BIT_ORDER_MSB;
1508 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1510 struct MouseCursorInfo *cursor;
1511 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1512 int header_lines = 4;
1515 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1517 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1520 for (y = 0; y < cursor->width; y++)
1522 for (x = 0; x < cursor->height; x++)
1525 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1530 cursor->data[i] = cursor->mask[i] = 0;
1533 switch (image[header_lines + y][x])
1536 cursor->data[i] |= bit_mask;
1537 cursor->mask[i] |= bit_mask;
1541 cursor->mask[i] |= bit_mask;
1550 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1555 void SetMouseCursor(int mode)
1557 static struct MouseCursorInfo *cursor_none = NULL;
1558 static struct MouseCursorInfo *cursor_playfield = NULL;
1559 struct MouseCursorInfo *cursor_new;
1560 int mode_final = mode;
1562 if (cursor_none == NULL)
1563 cursor_none = get_cursor_from_image(cursor_image_none);
1565 if (cursor_playfield == NULL)
1566 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1568 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1569 mode_final = gfx.cursor_mode_override;
1571 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1572 mode_final == CURSOR_NONE ? cursor_none :
1573 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1575 SDLSetMouseCursor(cursor_new);
1577 gfx.cursor_mode = mode;
1578 gfx.cursor_mode_final = mode_final;
1581 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1583 // mouse events do not contain logical screen size corrections yet
1584 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1586 mouse_x -= video.screen_xoffset;
1587 mouse_y -= video.screen_yoffset;
1589 gfx.mouse_x = mouse_x;
1590 gfx.mouse_y = mouse_y;
1593 void UpdateMousePosition(void)
1595 int mouse_x, mouse_y;
1598 SDL_GetMouseState(&mouse_x, &mouse_y);
1600 UpdateRawMousePosition(mouse_x, mouse_y);
1604 // ============================================================================
1606 // ============================================================================
1608 void OpenAudio(void)
1610 // always start with reliable default values
1611 audio.sound_available = FALSE;
1612 audio.music_available = FALSE;
1613 audio.loops_available = FALSE;
1615 audio.sound_enabled = FALSE;
1616 audio.sound_deactivated = FALSE;
1618 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1619 audio.mixer_pid = 0;
1620 audio.device_name = NULL;
1621 audio.device_fd = -1;
1623 audio.num_channels = 0;
1624 audio.music_channel = 0;
1625 audio.first_sound_channel = 0;
1630 void CloseAudio(void)
1634 audio.sound_enabled = FALSE;
1637 void SetAudioMode(boolean enabled)
1639 if (!audio.sound_available)
1642 audio.sound_enabled = enabled;
1646 // ============================================================================
1648 // ============================================================================
1650 void InitEventFilter(EventFilter filter_function)
1652 SDL_SetEventFilter(filter_function, NULL);
1655 boolean PendingEvent(void)
1657 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1660 void WaitEvent(Event *event)
1662 SDLWaitEvent(event);
1665 void PeekEvent(Event *event)
1667 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1670 void PumpEvents(void)
1675 void CheckQuitEvent(void)
1677 if (SDL_QuitRequested())
1678 program.exit_function(0);
1681 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1683 // key up/down events in SDL2 do not return text characters anymore
1684 return event->keysym.sym;
1687 KeyMod HandleKeyModState(Key key, int key_status)
1689 static KeyMod current_modifiers = KMOD_None;
1691 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1693 KeyMod new_modifier = KMOD_None;
1698 new_modifier = KMOD_Shift_L;
1701 new_modifier = KMOD_Shift_R;
1703 case KSYM_Control_L:
1704 new_modifier = KMOD_Control_L;
1706 case KSYM_Control_R:
1707 new_modifier = KMOD_Control_R;
1710 new_modifier = KMOD_Meta_L;
1713 new_modifier = KMOD_Meta_R;
1716 new_modifier = KMOD_Alt_L;
1719 new_modifier = KMOD_Alt_R;
1725 if (key_status == KEY_PRESSED)
1726 current_modifiers |= new_modifier;
1728 current_modifiers &= ~new_modifier;
1731 return current_modifiers;
1734 KeyMod GetKeyModState(void)
1736 return (KeyMod)SDL_GetModState();
1739 KeyMod GetKeyModStateFromEvents(void)
1741 /* always use key modifier state as tracked from key events (this is needed
1742 if the modifier key event was injected into the event queue, but the key
1743 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1744 query the keys as held pressed on the keyboard) -- this case is currently
1745 only used to filter out clipboard insert events from "True X-Mouse" tool */
1747 return HandleKeyModState(KSYM_UNDEFINED, 0);
1750 void StartTextInput(int x, int y, int width, int height)
1752 #if defined(HAS_SCREEN_KEYBOARD)
1753 SDL_StartTextInput();
1755 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1757 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1758 video.shifted_up_delay = SDL_GetTicks();
1759 video.shifted_up = TRUE;
1764 void StopTextInput(void)
1766 #if defined(HAS_SCREEN_KEYBOARD)
1767 SDL_StopTextInput();
1769 if (video.shifted_up)
1771 video.shifted_up_pos = 0;
1772 video.shifted_up_delay = SDL_GetTicks();
1773 video.shifted_up = FALSE;
1778 void PushUserEvent(int code, int value1, int value2)
1782 SDL_memset(&event, 0, sizeof(event));
1784 event.type = EVENT_USER;
1786 event.value1 = value1;
1787 event.value2 = value2;
1789 SDL_PushEvent((SDL_Event *)&event);
1793 // ============================================================================
1794 // joystick functions
1795 // ============================================================================
1797 void InitJoysticks(void)
1801 #if defined(NO_JOYSTICK)
1802 return; // joysticks generally deactivated by compile-time directive
1805 // always start with reliable default values
1806 joystick.status = JOYSTICK_NOT_AVAILABLE;
1807 for (i = 0; i < MAX_PLAYERS; i++)
1808 joystick.nr[i] = -1; // no joystick configured
1813 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1815 return SDLReadJoystick(nr, x, y, b1, b2);
1818 boolean CheckJoystickOpened(int nr)
1820 return SDLCheckJoystickOpened(nr);
1823 void ClearJoystickState(void)
1825 SDLClearJoystickState();