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;
118 network.server_thread = NULL;
119 network.is_server_thread = FALSE;
122 void InitRuntimeInfo()
124 #if defined(HAS_TOUCH_DEVICE)
125 runtime.uses_touch_device = TRUE;
127 runtime.uses_touch_device = FALSE;
131 void InitScoresInfo(void)
133 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
135 program.global_scores = directoryExists(global_scores_dir);
136 program.many_scores_per_name = !program.global_scores;
141 if (program.global_scores)
143 Debug("internal:path", "Using global, multi-user scores directory '%s'.",
145 Debug("internal:path", "Remove to enable single-user scores directory.");
146 Debug("internal:path", "(This enables multipe score entries per user.)");
150 Debug("internal:path", "Using private, single-user scores directory.");
155 free(global_scores_dir);
158 void SetWindowTitle(void)
160 program.window_title = program.window_title_function();
165 void InitWindowTitleFunction(char *(*window_title_function)(void))
167 program.window_title_function = window_title_function;
170 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
172 program.exit_message_function = exit_message_function;
175 void InitExitFunction(void (*exit_function)(int))
177 program.exit_function = exit_function;
179 // set signal handlers to custom exit function
180 // signal(SIGINT, exit_function);
181 signal(SIGTERM, exit_function);
183 // set exit function to automatically cleanup SDL stuff after exit()
187 void InitPlatformDependentStuff(void)
189 // this is initialized in GetOptions(), but may already be used before
190 options.verbose = TRUE;
194 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
196 if (SDL_Init(sdl_init_flags) < 0)
197 Fail("SDL_Init() failed: %s", SDL_GetError());
202 void ClosePlatformDependentStuff(void)
207 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
208 int real_sx, int real_sy,
209 int full_sxsize, int full_sysize,
210 Bitmap *field_save_buffer)
216 gfx.real_sx = real_sx;
217 gfx.real_sy = real_sy;
218 gfx.full_sxsize = full_sxsize;
219 gfx.full_sysize = full_sysize;
221 gfx.field_save_buffer = field_save_buffer;
223 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
224 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
227 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
229 gfx.game_tile_size = game_tile_size;
230 gfx.standard_tile_size = standard_tile_size;
233 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
241 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
249 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
257 void InitGfxWindowInfo(int win_xsize, int win_ysize)
259 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
261 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
263 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
265 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
266 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
267 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
268 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
270 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
273 gfx.win_xsize = win_xsize;
274 gfx.win_ysize = win_ysize;
276 gfx.background_bitmap_mask = REDRAW_NONE;
279 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
281 // currently only used by MSDOS code to alloc VRAM buffer, if available
282 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
283 gfx.scrollbuffer_width = scrollbuffer_width;
284 gfx.scrollbuffer_height = scrollbuffer_height;
287 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
289 gfx.clipping_enabled = enabled;
292 gfx.clip_width = width;
293 gfx.clip_height = height;
296 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
298 gfx.draw_busy_anim_function = draw_busy_anim_function;
301 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
303 gfx.draw_global_anim_function = draw_global_anim_function;
306 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
308 gfx.draw_global_border_function = draw_global_border_function;
311 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
313 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
316 void InitGfxCustomArtworkInfo(void)
318 gfx.override_level_graphics = FALSE;
319 gfx.override_level_sounds = FALSE;
320 gfx.override_level_music = FALSE;
322 gfx.draw_init_text = TRUE;
325 void InitGfxOtherSettings(void)
327 gfx.cursor_mode = CURSOR_DEFAULT;
328 gfx.cursor_mode_override = CURSOR_UNDEFINED;
329 gfx.cursor_mode_final = gfx.cursor_mode;
331 // prevent initially displaying custom mouse cursor in upper left corner
332 gfx.mouse_x = POS_OFFSCREEN;
333 gfx.mouse_y = POS_OFFSCREEN;
336 void InitTileCursorInfo(void)
338 tile_cursor.enabled = FALSE;
339 tile_cursor.active = FALSE;
340 tile_cursor.moving = FALSE;
342 tile_cursor.xpos = 0;
343 tile_cursor.ypos = 0;
346 tile_cursor.target_x = 0;
347 tile_cursor.target_y = 0;
352 tile_cursor.xsn_debug = FALSE;
355 void InitOverlayInfo(void)
357 overlay.enabled = FALSE;
358 overlay.active = FALSE;
360 overlay.show_grid = FALSE;
362 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
363 overlay.grid_button_action = JOY_NO_ACTION;
365 SetOverlayGridSizeAndButtons();
367 #if defined(USE_TOUCH_INPUT_OVERLAY)
368 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
369 overlay.enabled = TRUE;
373 void SetOverlayGridSizeAndButtons(void)
375 int nr = GRID_ACTIVE_NR();
378 overlay.grid_xsize = setup.touch.grid_xsize[nr];
379 overlay.grid_ysize = setup.touch.grid_ysize[nr];
381 for (x = 0; x < MAX_GRID_XSIZE; x++)
382 for (y = 0; y < MAX_GRID_YSIZE; y++)
383 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
386 void SetTileCursorEnabled(boolean enabled)
388 tile_cursor.enabled = enabled;
391 void SetTileCursorActive(boolean active)
393 tile_cursor.active = active;
396 void SetTileCursorTargetXY(int x, int y)
398 // delayed placement of tile selection cursor at target position
399 // (tile cursor will be moved to target position step by step)
401 tile_cursor.xpos = x;
402 tile_cursor.ypos = y;
403 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
404 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
406 tile_cursor.moving = TRUE;
409 void SetTileCursorXY(int x, int y)
411 // immediate placement of tile selection cursor at target position
413 SetTileCursorTargetXY(x, y);
415 tile_cursor.x = tile_cursor.target_x;
416 tile_cursor.y = tile_cursor.target_y;
418 tile_cursor.moving = FALSE;
421 void SetTileCursorSXSY(int sx, int sy)
427 void SetOverlayEnabled(boolean enabled)
429 overlay.enabled = enabled;
432 void SetOverlayActive(boolean active)
434 overlay.active = active;
437 void SetOverlayShowGrid(boolean show_grid)
439 overlay.show_grid = show_grid;
441 SetOverlayActive(show_grid);
444 SetOverlayEnabled(TRUE);
447 boolean GetOverlayEnabled(void)
449 return overlay.enabled;
452 boolean GetOverlayActive(void)
454 return overlay.active;
457 void SetDrawDeactivationMask(int draw_deactivation_mask)
459 gfx.draw_deactivation_mask = draw_deactivation_mask;
462 int GetDrawDeactivationMask(void)
464 return gfx.draw_deactivation_mask;
467 void SetDrawBackgroundMask(int draw_background_mask)
469 gfx.draw_background_mask = draw_background_mask;
472 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
474 if (background_bitmap_tile != NULL)
475 gfx.background_bitmap_mask |= mask;
477 gfx.background_bitmap_mask &= ~mask;
479 if (background_bitmap_tile == NULL) // empty background requested
482 if (mask == REDRAW_ALL)
483 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
484 0, 0, video.width, video.height);
485 else if (mask == REDRAW_FIELD)
486 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
487 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
488 else if (mask == REDRAW_DOOR_1)
489 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
490 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
493 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
495 // remove every mask before setting mask for window
496 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
497 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
498 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
501 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
503 // remove window area mask before setting mask for main area
504 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
505 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
506 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
509 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
511 // remove window area mask before setting mask for door area
512 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
513 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
514 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
518 // ============================================================================
520 // ============================================================================
522 static int GetRealDepth(int depth)
524 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
527 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
528 int width, int height, Pixel color)
530 SDLFillRectangle(bitmap, x, y, width, height, color);
532 if (bitmap == backbuffer)
533 SetRedrawMaskFromArea(x, y, width, height);
536 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
537 int src_x, int src_y, int width, int height,
538 int dst_x, int dst_y, int mask_mode)
540 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
541 dst_x, dst_y, mask_mode);
543 if (dst_bitmap == backbuffer)
544 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
547 void LimitScreenUpdates(boolean enable)
549 SDLLimitScreenUpdates(enable);
552 void InitVideoDefaults(void)
554 video.default_depth = 32;
557 void InitVideoDisplay(void)
559 if (program.headless)
562 SDLInitVideoDisplay();
566 void CloseVideoDisplay(void)
568 KeyboardAutoRepeatOn();
570 SDL_QuitSubSystem(SDL_INIT_VIDEO);
573 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
576 video.height = height;
577 video.depth = GetRealDepth(depth);
579 video.screen_width = width;
580 video.screen_height = height;
581 video.screen_xoffset = 0;
582 video.screen_yoffset = 0;
584 video.fullscreen_available = FULLSCREEN_STATUS;
585 video.fullscreen_enabled = FALSE;
587 video.window_scaling_available = WINDOW_SCALING_STATUS;
589 video.frame_counter = 0;
590 video.frame_delay = 0;
591 video.frame_delay_value = GAME_FRAME_DELAY;
593 video.shifted_up = FALSE;
594 video.shifted_up_pos = 0;
595 video.shifted_up_pos_last = 0;
596 video.shifted_up_delay = 0;
597 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
599 SDLInitVideoBuffer(fullscreen);
601 video.initialized = !program.headless;
606 static void FreeBitmapPointers(Bitmap *bitmap)
611 SDLFreeBitmapPointers(bitmap);
613 checked_free(bitmap->source_filename);
614 bitmap->source_filename = NULL;
617 static void TransferBitmapPointers(Bitmap *src_bitmap,
620 if (src_bitmap == NULL || dst_bitmap == NULL)
623 FreeBitmapPointers(dst_bitmap);
625 *dst_bitmap = *src_bitmap;
628 void FreeBitmap(Bitmap *bitmap)
633 FreeBitmapPointers(bitmap);
638 Bitmap *CreateBitmapStruct(void)
640 return checked_calloc(sizeof(Bitmap));
643 Bitmap *CreateBitmap(int width, int height, int depth)
645 Bitmap *new_bitmap = CreateBitmapStruct();
646 int real_width = MAX(1, width); // prevent zero bitmap width
647 int real_height = MAX(1, height); // prevent zero bitmap height
648 int real_depth = GetRealDepth(depth);
650 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
652 new_bitmap->width = real_width;
653 new_bitmap->height = real_height;
658 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
662 // if new bitmap size fits into old one, no need to re-create it
663 if (width <= (*bitmap)->width &&
664 height <= (*bitmap)->height)
667 // else adjust size so that old and new bitmap size fit into it
668 width = MAX(width, (*bitmap)->width);
669 height = MAX(height, (*bitmap)->height);
672 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
676 *bitmap = new_bitmap;
680 TransferBitmapPointers(new_bitmap, *bitmap);
686 static void CloseWindow(DrawWindow *window)
691 void SetRedrawMaskFromArea(int x, int y, int width, int height)
695 int x2 = x + width - 1;
696 int y2 = y + height - 1;
698 if (width == 0 || height == 0)
701 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
702 redraw_mask |= REDRAW_FIELD;
703 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
704 redraw_mask |= REDRAW_DOOR_1;
705 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
706 redraw_mask |= REDRAW_DOOR_2;
707 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
708 redraw_mask |= REDRAW_DOOR_3;
710 redraw_mask = REDRAW_ALL;
713 static boolean CheckDrawingArea(int x, int y, int width, int height,
716 if (draw_mask == REDRAW_NONE)
719 if (draw_mask & REDRAW_ALL)
722 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
725 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
728 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
731 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
737 boolean DrawingDeactivatedField(void)
739 if (program.headless)
742 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
748 boolean DrawingDeactivated(int x, int y, int width, int height)
750 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
753 boolean DrawingOnBackground(int x, int y)
755 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
756 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
759 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
760 int *width, int *height, boolean is_dest)
762 int clip_x, clip_y, clip_width, clip_height;
764 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
766 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
767 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
768 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
769 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
775 clip_width = bitmap->width;
776 clip_height = bitmap->height;
779 // skip if rectangle completely outside bitmap
781 if (*x + *width <= clip_x ||
782 *y + *height <= clip_y ||
783 *x >= clip_x + clip_width ||
784 *y >= clip_y + clip_height)
787 // clip if rectangle overlaps bitmap
791 *width -= clip_x - *x;
794 else if (*x + *width > clip_x + clip_width)
796 *width = clip_x + clip_width - *x;
801 *height -= clip_y - *y;
804 else if (*y + *height > clip_y + clip_height)
806 *height = clip_y + clip_height - *y;
812 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
813 int src_x, int src_y, int width, int height,
814 int dst_x, int dst_y)
816 int dst_x_unclipped = dst_x;
817 int dst_y_unclipped = dst_y;
819 if (program.headless)
822 if (src_bitmap == NULL || dst_bitmap == NULL)
825 if (DrawingDeactivated(dst_x, dst_y, width, height))
828 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
829 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
832 // source x/y might need adjustment if destination x/y was clipped top/left
833 src_x += dst_x - dst_x_unclipped;
834 src_y += dst_y - dst_y_unclipped;
836 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
837 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
838 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
839 but is already fixed in SVN and should therefore finally be fixed with
840 the next official SDL release, which is probably version 1.2.14.) */
841 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
843 if (src_bitmap == dst_bitmap)
845 // needed when blitting directly to same bitmap -- should not be needed with
846 // recent SDL libraries, but apparently does not work in 1.2.11 directly
848 static Bitmap *tmp_bitmap = NULL;
849 static int tmp_bitmap_xsize = 0;
850 static int tmp_bitmap_ysize = 0;
852 // start with largest static bitmaps for initial bitmap size ...
853 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
855 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
856 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
859 // ... and allow for later re-adjustments due to custom artwork bitmaps
860 if (src_bitmap->width > tmp_bitmap_xsize ||
861 src_bitmap->height > tmp_bitmap_ysize)
863 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
864 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
866 FreeBitmap(tmp_bitmap);
871 if (tmp_bitmap == NULL)
872 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
875 sysCopyArea(src_bitmap, tmp_bitmap,
876 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
877 sysCopyArea(tmp_bitmap, dst_bitmap,
878 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
883 sysCopyArea(src_bitmap, dst_bitmap,
884 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
887 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
888 int src_x, int src_y, int src_width, int src_height,
889 int dst_x, int dst_y, int dst_width, int dst_height)
891 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
892 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
893 int dst_xsize = dst_width;
894 int dst_ysize = dst_height;
895 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
896 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
899 for (y = 0; y < src_ysteps; y++)
901 for (x = 0; x < src_xsteps; x++)
903 int draw_x = dst_x + x * src_xsize;
904 int draw_y = dst_y + y * src_ysize;
905 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
906 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
908 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
914 void FadeRectangle(int x, int y, int width, int height,
915 int fade_mode, int fade_delay, int post_delay,
916 void (*draw_border_function)(void))
918 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
919 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
922 SDLFadeRectangle(x, y, width, height,
923 fade_mode, fade_delay, post_delay, draw_border_function);
926 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
929 if (DrawingDeactivated(x, y, width, height))
932 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
935 sysFillRectangle(bitmap, x, y, width, height, color);
938 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
940 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
943 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
944 int width, int height)
946 if (DrawingOnBackground(x, y))
947 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
949 ClearRectangle(bitmap, x, y, width, height);
952 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
953 int src_x, int src_y, int width, int height,
954 int dst_x, int dst_y)
956 if (DrawingDeactivated(dst_x, dst_y, width, height))
959 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
960 dst_x, dst_y, BLIT_MASKED);
963 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
964 int src_x, int src_y, int width, int height,
965 int dst_x, int dst_y)
967 if (DrawingOnBackground(dst_x, dst_y))
970 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
974 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
978 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
982 void BlitTexture(Bitmap *bitmap,
983 int src_x, int src_y, int width, int height,
984 int dst_x, int dst_y)
989 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
993 void BlitTextureMasked(Bitmap *bitmap,
994 int src_x, int src_y, int width, int height,
995 int dst_x, int dst_y)
1000 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1004 void BlitToScreen(Bitmap *bitmap,
1005 int src_x, int src_y, int width, int height,
1006 int dst_x, int dst_y)
1011 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1012 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1013 width, height, dst_x, dst_y);
1015 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1018 void BlitToScreenMasked(Bitmap *bitmap,
1019 int src_x, int src_y, int width, int height,
1020 int dst_x, int dst_y)
1025 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1026 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1027 width, height, dst_x, dst_y);
1029 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1032 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1035 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1038 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1041 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1044 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1045 int to_x, int to_y, Pixel pixel, int line_width)
1049 if (program.headless)
1052 for (x = 0; x < line_width; x++)
1054 for (y = 0; y < line_width; y++)
1056 int dx = x - line_width / 2;
1057 int dy = y - line_width / 2;
1059 if ((x == 0 && y == 0) ||
1060 (x == 0 && y == line_width - 1) ||
1061 (x == line_width - 1 && y == 0) ||
1062 (x == line_width - 1 && y == line_width - 1))
1066 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1071 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1076 for (i = 0; i < num_points - 1; i++)
1077 DrawLine(bitmap, points[i].x, points[i].y,
1078 points[i + 1].x, points[i + 1].y, pixel, line_width);
1081 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1085 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1087 if (program.headless)
1090 if (x < 0 || x >= bitmap->width ||
1091 y < 0 || y >= bitmap->height)
1094 return SDLGetPixel(bitmap, x, y);
1097 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1098 unsigned int color_g, unsigned int color_b)
1100 if (program.headless)
1103 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1106 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1108 unsigned int color_r = (color >> 16) & 0xff;
1109 unsigned int color_g = (color >> 8) & 0xff;
1110 unsigned int color_b = (color >> 0) & 0xff;
1112 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1115 void KeyboardAutoRepeatOn(void)
1117 keyrepeat_status = TRUE;
1120 void KeyboardAutoRepeatOff(void)
1122 keyrepeat_status = FALSE;
1125 boolean SetVideoMode(boolean fullscreen)
1127 return SDLSetVideoMode(fullscreen);
1130 void SetVideoFrameDelay(unsigned int frame_delay_value)
1132 video.frame_delay_value = frame_delay_value;
1135 unsigned int GetVideoFrameDelay(void)
1137 return video.frame_delay_value;
1140 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1142 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1143 (!fullscreen && video.fullscreen_enabled))
1144 fullscreen = SetVideoMode(fullscreen);
1149 Bitmap *LoadImage(char *filename)
1153 new_bitmap = SDLLoadImage(filename);
1156 new_bitmap->source_filename = getStringCopy(filename);
1161 Bitmap *LoadCustomImage(char *basename)
1163 char *filename = getCustomImageFilename(basename);
1166 if (filename == NULL)
1167 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1169 if ((new_bitmap = LoadImage(filename)) == NULL)
1170 Fail("LoadImage('%s') failed", basename);
1175 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1177 char *filename = getCustomImageFilename(basename);
1180 if (filename == NULL) // (should never happen)
1182 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1187 if (strEqual(filename, bitmap->source_filename))
1189 // The old and new image are the same (have the same filename and path).
1190 // This usually means that this image does not exist in this graphic set
1191 // and a fallback to the existing image is done.
1196 if ((new_bitmap = LoadImage(filename)) == NULL)
1198 Warn("LoadImage('%s') failed", basename);
1203 if (bitmap->width != new_bitmap->width ||
1204 bitmap->height != new_bitmap->height)
1206 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1209 FreeBitmap(new_bitmap);
1214 TransferBitmapPointers(new_bitmap, bitmap);
1218 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1220 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1223 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1225 if (bitmaps[IMG_BITMAP_CUSTOM])
1227 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1229 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1232 if (gfx.game_tile_size == gfx.standard_tile_size)
1234 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1239 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1240 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1241 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1243 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1245 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1246 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1249 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1250 int tile_size, boolean create_small_bitmaps)
1252 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1253 Bitmap *tmp_bitmap_final = NULL;
1254 Bitmap *tmp_bitmap_0 = NULL;
1255 Bitmap *tmp_bitmap_1 = NULL;
1256 Bitmap *tmp_bitmap_2 = NULL;
1257 Bitmap *tmp_bitmap_4 = NULL;
1258 Bitmap *tmp_bitmap_8 = NULL;
1259 Bitmap *tmp_bitmap_16 = NULL;
1260 Bitmap *tmp_bitmap_32 = NULL;
1261 int width_final, height_final;
1262 int width_0, height_0;
1263 int width_1, height_1;
1264 int width_2, height_2;
1265 int width_4, height_4;
1266 int width_8, height_8;
1267 int width_16, height_16;
1268 int width_32, height_32;
1269 int old_width, old_height;
1272 print_timestamp_init("CreateScaledBitmaps");
1274 old_width = old_bitmap->width;
1275 old_height = old_bitmap->height;
1277 // calculate new image dimensions for final image size
1278 width_final = old_width * zoom_factor;
1279 height_final = old_height * zoom_factor;
1281 // get image with final size (this might require scaling up)
1282 // ("final" size may result in non-standard tile size image)
1283 if (zoom_factor != 1)
1284 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1286 tmp_bitmap_final = old_bitmap;
1288 UPDATE_BUSY_STATE();
1290 width_0 = width_1 = width_final;
1291 height_0 = height_1 = height_final;
1293 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1295 if (create_small_bitmaps)
1297 // check if we have a non-gameplay tile size image
1298 if (tile_size != gfx.game_tile_size)
1300 // get image with gameplay tile size
1301 width_0 = width_final * gfx.game_tile_size / tile_size;
1302 height_0 = height_final * gfx.game_tile_size / tile_size;
1304 if (width_0 == old_width)
1305 tmp_bitmap_0 = old_bitmap;
1306 else if (width_0 == width_final)
1307 tmp_bitmap_0 = tmp_bitmap_final;
1309 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1311 UPDATE_BUSY_STATE();
1314 // check if we have a non-standard tile size image
1315 if (tile_size != gfx.standard_tile_size)
1317 // get image with standard tile size
1318 width_1 = width_final * gfx.standard_tile_size / tile_size;
1319 height_1 = height_final * gfx.standard_tile_size / tile_size;
1321 if (width_1 == old_width)
1322 tmp_bitmap_1 = old_bitmap;
1323 else if (width_1 == width_final)
1324 tmp_bitmap_1 = tmp_bitmap_final;
1325 else if (width_1 == width_0)
1326 tmp_bitmap_1 = tmp_bitmap_0;
1328 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1330 UPDATE_BUSY_STATE();
1333 // calculate new image dimensions for small images
1334 width_2 = width_1 / 2;
1335 height_2 = height_1 / 2;
1336 width_4 = width_1 / 4;
1337 height_4 = height_1 / 4;
1338 width_8 = width_1 / 8;
1339 height_8 = height_1 / 8;
1340 width_16 = width_1 / 16;
1341 height_16 = height_1 / 16;
1342 width_32 = width_1 / 32;
1343 height_32 = height_1 / 32;
1345 // get image with 1/2 of normal size (for use in the level editor)
1346 if (width_2 == old_width)
1347 tmp_bitmap_2 = old_bitmap;
1349 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1351 UPDATE_BUSY_STATE();
1353 // get image with 1/4 of normal size (for use in the level editor)
1354 if (width_4 == old_width)
1355 tmp_bitmap_4 = old_bitmap;
1357 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1359 UPDATE_BUSY_STATE();
1361 // get image with 1/8 of normal size (for use on the preview screen)
1362 if (width_8 == old_width)
1363 tmp_bitmap_8 = old_bitmap;
1365 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1367 UPDATE_BUSY_STATE();
1369 // get image with 1/16 of normal size (for use on the preview screen)
1370 if (width_16 == old_width)
1371 tmp_bitmap_16 = old_bitmap;
1373 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1375 UPDATE_BUSY_STATE();
1377 // get image with 1/32 of normal size (for use on the preview screen)
1378 if (width_32 == old_width)
1379 tmp_bitmap_32 = old_bitmap;
1381 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1383 UPDATE_BUSY_STATE();
1385 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1386 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1387 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1388 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1389 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1390 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1392 if (width_0 != width_1)
1393 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1395 if (bitmaps[IMG_BITMAP_CUSTOM])
1396 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1398 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1400 boolean free_old_bitmap = TRUE;
1402 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1403 if (bitmaps[i] == old_bitmap)
1404 free_old_bitmap = FALSE;
1406 if (free_old_bitmap)
1408 // copy image filename from old to new standard sized bitmap
1409 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1410 getStringCopy(old_bitmap->source_filename);
1412 FreeBitmap(old_bitmap);
1417 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1420 UPDATE_BUSY_STATE();
1422 print_timestamp_done("CreateScaledBitmaps");
1425 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1428 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1431 void CreateBitmapTextures(Bitmap **bitmaps)
1433 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1436 void FreeBitmapTextures(Bitmap **bitmaps)
1438 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1441 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1443 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1447 // ----------------------------------------------------------------------------
1448 // mouse pointer functions
1449 // ----------------------------------------------------------------------------
1451 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1453 // XPM image definitions
1454 static const char *cursor_image_none[] =
1456 // width height num_colors chars_per_pixel
1486 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1487 static const char *cursor_image_dot[] =
1489 // width height num_colors chars_per_pixel
1518 static const char **cursor_image_playfield = cursor_image_dot;
1520 // some people complained about a "white dot" on the screen and thought it
1521 // was a graphical error... OK, let's just remove the whole pointer :-)
1522 static const char **cursor_image_playfield = cursor_image_none;
1525 static const int cursor_bit_order = BIT_ORDER_MSB;
1527 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1529 struct MouseCursorInfo *cursor;
1530 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1531 int header_lines = 4;
1534 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1536 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1539 for (y = 0; y < cursor->width; y++)
1541 for (x = 0; x < cursor->height; x++)
1544 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1549 cursor->data[i] = cursor->mask[i] = 0;
1552 switch (image[header_lines + y][x])
1555 cursor->data[i] |= bit_mask;
1556 cursor->mask[i] |= bit_mask;
1560 cursor->mask[i] |= bit_mask;
1569 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1574 void SetMouseCursor(int mode)
1576 static struct MouseCursorInfo *cursor_none = NULL;
1577 static struct MouseCursorInfo *cursor_playfield = NULL;
1578 struct MouseCursorInfo *cursor_new;
1579 int mode_final = mode;
1581 if (cursor_none == NULL)
1582 cursor_none = get_cursor_from_image(cursor_image_none);
1584 if (cursor_playfield == NULL)
1585 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1587 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1588 mode_final = gfx.cursor_mode_override;
1590 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1591 mode_final == CURSOR_NONE ? cursor_none :
1592 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1594 SDLSetMouseCursor(cursor_new);
1596 gfx.cursor_mode = mode;
1597 gfx.cursor_mode_final = mode_final;
1600 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1602 // mouse events do not contain logical screen size corrections yet
1603 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1605 mouse_x -= video.screen_xoffset;
1606 mouse_y -= video.screen_yoffset;
1608 gfx.mouse_x = mouse_x;
1609 gfx.mouse_y = mouse_y;
1612 void UpdateMousePosition(void)
1614 int mouse_x, mouse_y;
1617 SDL_GetMouseState(&mouse_x, &mouse_y);
1619 UpdateRawMousePosition(mouse_x, mouse_y);
1623 // ============================================================================
1625 // ============================================================================
1627 void OpenAudio(void)
1629 // always start with reliable default values
1630 audio.sound_available = FALSE;
1631 audio.music_available = FALSE;
1632 audio.loops_available = FALSE;
1634 audio.sound_enabled = FALSE;
1635 audio.sound_deactivated = FALSE;
1637 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1638 audio.mixer_pid = 0;
1639 audio.device_name = NULL;
1640 audio.device_fd = -1;
1642 audio.num_channels = 0;
1643 audio.music_channel = 0;
1644 audio.first_sound_channel = 0;
1649 void CloseAudio(void)
1653 audio.sound_enabled = FALSE;
1656 void SetAudioMode(boolean enabled)
1658 if (!audio.sound_available)
1661 audio.sound_enabled = enabled;
1665 // ============================================================================
1667 // ============================================================================
1669 void InitEventFilter(EventFilter filter_function)
1671 SDL_SetEventFilter(filter_function, NULL);
1674 boolean PendingEvent(void)
1676 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1679 void WaitEvent(Event *event)
1681 SDLWaitEvent(event);
1684 void PeekEvent(Event *event)
1686 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1689 void PumpEvents(void)
1694 void CheckQuitEvent(void)
1696 if (SDL_QuitRequested())
1697 program.exit_function(0);
1700 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1702 // key up/down events in SDL2 do not return text characters anymore
1703 return event->keysym.sym;
1706 KeyMod HandleKeyModState(Key key, int key_status)
1708 static KeyMod current_modifiers = KMOD_None;
1710 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1712 KeyMod new_modifier = KMOD_None;
1717 new_modifier = KMOD_Shift_L;
1720 new_modifier = KMOD_Shift_R;
1722 case KSYM_Control_L:
1723 new_modifier = KMOD_Control_L;
1725 case KSYM_Control_R:
1726 new_modifier = KMOD_Control_R;
1729 new_modifier = KMOD_Meta_L;
1732 new_modifier = KMOD_Meta_R;
1735 new_modifier = KMOD_Alt_L;
1738 new_modifier = KMOD_Alt_R;
1744 if (key_status == KEY_PRESSED)
1745 current_modifiers |= new_modifier;
1747 current_modifiers &= ~new_modifier;
1750 return current_modifiers;
1753 KeyMod GetKeyModState(void)
1755 return (KeyMod)SDL_GetModState();
1758 KeyMod GetKeyModStateFromEvents(void)
1760 /* always use key modifier state as tracked from key events (this is needed
1761 if the modifier key event was injected into the event queue, but the key
1762 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1763 query the keys as held pressed on the keyboard) -- this case is currently
1764 only used to filter out clipboard insert events from "True X-Mouse" tool */
1766 return HandleKeyModState(KSYM_UNDEFINED, 0);
1769 void StartTextInput(int x, int y, int width, int height)
1771 textinput_status = TRUE;
1773 #if defined(HAS_SCREEN_KEYBOARD)
1774 SDL_StartTextInput();
1776 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1778 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1779 video.shifted_up_delay = SDL_GetTicks();
1780 video.shifted_up = TRUE;
1785 void StopTextInput(void)
1787 textinput_status = FALSE;
1789 #if defined(HAS_SCREEN_KEYBOARD)
1790 SDL_StopTextInput();
1792 if (video.shifted_up)
1794 video.shifted_up_pos = 0;
1795 video.shifted_up_delay = SDL_GetTicks();
1796 video.shifted_up = FALSE;
1801 void PushUserEvent(int code, int value1, int value2)
1805 SDL_memset(&event, 0, sizeof(event));
1807 event.type = EVENT_USER;
1809 event.value1 = value1;
1810 event.value2 = value2;
1812 SDL_PushEvent((SDL_Event *)&event);
1816 // ============================================================================
1817 // joystick functions
1818 // ============================================================================
1820 void InitJoysticks(void)
1824 #if defined(NO_JOYSTICK)
1825 return; // joysticks generally deactivated by compile-time directive
1828 // always start with reliable default values
1829 joystick.status = JOYSTICK_NOT_AVAILABLE;
1830 for (i = 0; i < MAX_PLAYERS; i++)
1831 joystick.nr[i] = -1; // no joystick configured
1836 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1838 return SDLReadJoystick(nr, x, y, b1, b2);
1841 boolean CheckJoystickOpened(int nr)
1843 return SDLCheckJoystickOpened(nr);
1846 void ClearJoystickState(void)
1848 SDLClearJoystickState();