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;
45 LevelDirTree *leveldir_first_all = NULL;
46 LevelDirTree *leveldir_first = NULL;
47 LevelDirTree *leveldir_current = NULL;
50 struct LevelSetInfo levelset;
51 struct LevelStats level_stats[MAX_LEVELS];
53 DrawWindow *window = NULL;
54 DrawBuffer *backbuffer = NULL;
55 DrawBuffer *drawto = NULL;
57 int button_status = MB_NOT_PRESSED;
58 boolean motion_status = FALSE;
59 int wheel_steps = DEFAULT_WHEEL_STEPS;
60 boolean keyrepeat_status = TRUE;
61 boolean textinput_status = FALSE;
63 int redraw_mask = REDRAW_NONE;
68 // ============================================================================
69 // init/close functions
70 // ============================================================================
72 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
73 char *program_title, char *icon_title,
74 char *icon_filename, char *cookie_prefix,
75 char *program_version_string, int program_version)
77 program.command_basepath = getBasePath(argv0);
78 program.command_basename = getBaseName(argv0);
80 program.config_filename = config_filename;
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_path = getMainUserGameDataDir();
85 program.program_title = program_title;
86 program.window_title = "(undefined)";
87 program.icon_title = icon_title;
89 program.icon_filename = icon_filename;
91 program.cookie_prefix = cookie_prefix;
93 program.version_super = VERSION_SUPER(program_version);
94 program.version_major = VERSION_MAJOR(program_version);
95 program.version_minor = VERSION_MINOR(program_version);
96 program.version_patch = VERSION_PATCH(program_version);
97 program.version_ident = program_version;
99 program.version_string = program_version_string;
101 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
102 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
103 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
104 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
106 program.headless = FALSE;
109 void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
110 char *server_host, int server_port)
112 network.enabled = enabled;
113 network.connected = connected;
114 network.serveronly = serveronly;
116 network.server_host = server_host;
117 network.server_port = server_port;
119 network.server_thread = NULL;
120 network.is_server_thread = FALSE;
123 void InitRuntimeInfo()
125 #if defined(HAS_TOUCH_DEVICE)
126 runtime.uses_touch_device = TRUE;
128 runtime.uses_touch_device = FALSE;
132 void InitScoresInfo(void)
134 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
136 program.global_scores = directoryExists(global_scores_dir);
137 program.many_scores_per_name = !program.global_scores;
142 if (program.global_scores)
144 Debug("internal:path", "Using global, multi-user scores directory '%s'.",
146 Debug("internal:path", "Remove to enable single-user scores directory.");
147 Debug("internal:path", "(This enables multipe score entries per user.)");
151 Debug("internal:path", "Using private, single-user scores directory.");
156 free(global_scores_dir);
159 void SetWindowTitle(void)
161 program.window_title = program.window_title_function();
166 void InitWindowTitleFunction(char *(*window_title_function)(void))
168 program.window_title_function = window_title_function;
171 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
173 program.exit_message_function = exit_message_function;
176 void InitExitFunction(void (*exit_function)(int))
178 program.exit_function = exit_function;
180 // set signal handlers to custom exit function
181 // signal(SIGINT, exit_function);
182 signal(SIGTERM, exit_function);
184 // set exit function to automatically cleanup SDL stuff after exit()
188 void InitPlatformDependentStuff(void)
190 // this is initialized in GetOptions(), but may already be used before
191 options.verbose = TRUE;
195 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
197 if (SDL_Init(sdl_init_flags) < 0)
198 Fail("SDL_Init() failed: %s", SDL_GetError());
203 void ClosePlatformDependentStuff(void)
208 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
209 int real_sx, int real_sy,
210 int full_sxsize, int full_sysize,
211 Bitmap *field_save_buffer)
217 gfx.real_sx = real_sx;
218 gfx.real_sy = real_sy;
219 gfx.full_sxsize = full_sxsize;
220 gfx.full_sysize = full_sysize;
222 gfx.field_save_buffer = field_save_buffer;
224 SetDrawDeactivationMask(REDRAW_NONE); // do not deactivate drawing
225 SetDrawBackgroundMask(REDRAW_NONE); // deactivate masked drawing
228 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
230 gfx.game_tile_size = game_tile_size;
231 gfx.standard_tile_size = standard_tile_size;
234 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
242 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
250 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
258 void InitGfxWindowInfo(int win_xsize, int win_ysize)
260 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
262 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
264 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
266 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
267 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
268 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
269 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
271 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
274 gfx.win_xsize = win_xsize;
275 gfx.win_ysize = win_ysize;
277 gfx.background_bitmap_mask = REDRAW_NONE;
280 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
282 // currently only used by MSDOS code to alloc VRAM buffer, if available
283 // 2009-03-24: also (temporarily?) used for overlapping blit workaround
284 gfx.scrollbuffer_width = scrollbuffer_width;
285 gfx.scrollbuffer_height = scrollbuffer_height;
288 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
290 gfx.clipping_enabled = enabled;
293 gfx.clip_width = width;
294 gfx.clip_height = height;
297 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
299 gfx.draw_busy_anim_function = draw_busy_anim_function;
302 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
304 gfx.draw_global_anim_function = draw_global_anim_function;
307 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
309 gfx.draw_global_border_function = draw_global_border_function;
312 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
314 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
317 void InitGfxCustomArtworkInfo(void)
319 gfx.override_level_graphics = FALSE;
320 gfx.override_level_sounds = FALSE;
321 gfx.override_level_music = FALSE;
323 gfx.draw_init_text = TRUE;
326 void InitGfxOtherSettings(void)
328 gfx.cursor_mode = CURSOR_DEFAULT;
329 gfx.cursor_mode_override = CURSOR_UNDEFINED;
330 gfx.cursor_mode_final = gfx.cursor_mode;
332 // prevent initially displaying custom mouse cursor in upper left corner
333 gfx.mouse_x = POS_OFFSCREEN;
334 gfx.mouse_y = POS_OFFSCREEN;
337 void InitTileCursorInfo(void)
339 tile_cursor.enabled = FALSE;
340 tile_cursor.active = FALSE;
341 tile_cursor.moving = FALSE;
343 tile_cursor.xpos = 0;
344 tile_cursor.ypos = 0;
347 tile_cursor.target_x = 0;
348 tile_cursor.target_y = 0;
353 tile_cursor.xsn_debug = FALSE;
356 void InitOverlayInfo(void)
358 overlay.enabled = FALSE;
359 overlay.active = FALSE;
361 overlay.show_grid = FALSE;
363 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
364 overlay.grid_button_action = JOY_NO_ACTION;
366 SetOverlayGridSizeAndButtons();
368 #if defined(USE_TOUCH_INPUT_OVERLAY)
369 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
370 overlay.enabled = TRUE;
374 void SetOverlayGridSizeAndButtons(void)
376 int nr = GRID_ACTIVE_NR();
379 overlay.grid_xsize = setup.touch.grid_xsize[nr];
380 overlay.grid_ysize = setup.touch.grid_ysize[nr];
382 for (x = 0; x < MAX_GRID_XSIZE; x++)
383 for (y = 0; y < MAX_GRID_YSIZE; y++)
384 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
387 void SetTileCursorEnabled(boolean enabled)
389 tile_cursor.enabled = enabled;
392 void SetTileCursorActive(boolean active)
394 tile_cursor.active = active;
397 void SetTileCursorTargetXY(int x, int y)
399 // delayed placement of tile selection cursor at target position
400 // (tile cursor will be moved to target position step by step)
402 tile_cursor.xpos = x;
403 tile_cursor.ypos = y;
404 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
405 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
407 tile_cursor.moving = TRUE;
410 void SetTileCursorXY(int x, int y)
412 // immediate placement of tile selection cursor at target position
414 SetTileCursorTargetXY(x, y);
416 tile_cursor.x = tile_cursor.target_x;
417 tile_cursor.y = tile_cursor.target_y;
419 tile_cursor.moving = FALSE;
422 void SetTileCursorSXSY(int sx, int sy)
428 void SetOverlayEnabled(boolean enabled)
430 overlay.enabled = enabled;
433 void SetOverlayActive(boolean active)
435 overlay.active = active;
438 void SetOverlayShowGrid(boolean show_grid)
440 overlay.show_grid = show_grid;
442 SetOverlayActive(show_grid);
445 SetOverlayEnabled(TRUE);
448 boolean GetOverlayEnabled(void)
450 return overlay.enabled;
453 boolean GetOverlayActive(void)
455 return overlay.active;
458 void SetDrawDeactivationMask(int draw_deactivation_mask)
460 gfx.draw_deactivation_mask = draw_deactivation_mask;
463 int GetDrawDeactivationMask(void)
465 return gfx.draw_deactivation_mask;
468 void SetDrawBackgroundMask(int draw_background_mask)
470 gfx.draw_background_mask = draw_background_mask;
473 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
475 if (background_bitmap_tile != NULL)
476 gfx.background_bitmap_mask |= mask;
478 gfx.background_bitmap_mask &= ~mask;
480 if (background_bitmap_tile == NULL) // empty background requested
483 if (mask == REDRAW_ALL)
484 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
485 0, 0, video.width, video.height);
486 else if (mask == REDRAW_FIELD)
487 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
488 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
489 else if (mask == REDRAW_DOOR_1)
490 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
491 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
494 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
496 // remove every mask before setting mask for window
497 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
498 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
499 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
502 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
504 // remove window area mask before setting mask for main area
505 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
506 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
507 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
510 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
512 // remove window area mask before setting mask for door area
513 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
514 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
515 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
519 // ============================================================================
521 // ============================================================================
523 static int GetRealDepth(int depth)
525 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
528 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
529 int width, int height, Pixel color)
531 SDLFillRectangle(bitmap, x, y, width, height, color);
533 if (bitmap == backbuffer)
534 SetRedrawMaskFromArea(x, y, width, height);
537 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
538 int src_x, int src_y, int width, int height,
539 int dst_x, int dst_y, int mask_mode)
541 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
542 dst_x, dst_y, mask_mode);
544 if (dst_bitmap == backbuffer)
545 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
548 void LimitScreenUpdates(boolean enable)
550 SDLLimitScreenUpdates(enable);
553 void InitVideoDefaults(void)
555 video.default_depth = 32;
558 void InitVideoDisplay(void)
560 if (program.headless)
563 SDLInitVideoDisplay();
567 void CloseVideoDisplay(void)
569 KeyboardAutoRepeatOn();
571 SDL_QuitSubSystem(SDL_INIT_VIDEO);
574 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
577 video.height = height;
578 video.depth = GetRealDepth(depth);
580 video.screen_width = width;
581 video.screen_height = height;
582 video.screen_xoffset = 0;
583 video.screen_yoffset = 0;
585 video.fullscreen_available = FULLSCREEN_STATUS;
586 video.fullscreen_enabled = FALSE;
588 video.window_scaling_available = WINDOW_SCALING_STATUS;
590 video.frame_counter = 0;
591 video.frame_delay = 0;
592 video.frame_delay_value = GAME_FRAME_DELAY;
594 video.shifted_up = FALSE;
595 video.shifted_up_pos = 0;
596 video.shifted_up_pos_last = 0;
597 video.shifted_up_delay = 0;
598 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
600 SDLInitVideoBuffer(fullscreen);
602 video.initialized = !program.headless;
607 static void FreeBitmapPointers(Bitmap *bitmap)
612 SDLFreeBitmapPointers(bitmap);
614 checked_free(bitmap->source_filename);
615 bitmap->source_filename = NULL;
618 static void TransferBitmapPointers(Bitmap *src_bitmap,
621 if (src_bitmap == NULL || dst_bitmap == NULL)
624 FreeBitmapPointers(dst_bitmap);
626 *dst_bitmap = *src_bitmap;
629 void FreeBitmap(Bitmap *bitmap)
634 FreeBitmapPointers(bitmap);
639 Bitmap *CreateBitmapStruct(void)
641 return checked_calloc(sizeof(Bitmap));
644 Bitmap *CreateBitmap(int width, int height, int depth)
646 Bitmap *new_bitmap = CreateBitmapStruct();
647 int real_width = MAX(1, width); // prevent zero bitmap width
648 int real_height = MAX(1, height); // prevent zero bitmap height
649 int real_depth = GetRealDepth(depth);
651 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
653 new_bitmap->width = real_width;
654 new_bitmap->height = real_height;
659 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
663 // if new bitmap size fits into old one, no need to re-create it
664 if (width <= (*bitmap)->width &&
665 height <= (*bitmap)->height)
668 // else adjust size so that old and new bitmap size fit into it
669 width = MAX(width, (*bitmap)->width);
670 height = MAX(height, (*bitmap)->height);
673 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
677 *bitmap = new_bitmap;
681 TransferBitmapPointers(new_bitmap, *bitmap);
687 static void CloseWindow(DrawWindow *window)
692 void SetRedrawMaskFromArea(int x, int y, int width, int height)
696 int x2 = x + width - 1;
697 int y2 = y + height - 1;
699 if (width == 0 || height == 0)
702 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
703 redraw_mask |= REDRAW_FIELD;
704 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
705 redraw_mask |= REDRAW_DOOR_1;
706 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
707 redraw_mask |= REDRAW_DOOR_2;
708 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
709 redraw_mask |= REDRAW_DOOR_3;
711 redraw_mask = REDRAW_ALL;
714 static boolean CheckDrawingArea(int x, int y, int width, int height,
717 if (draw_mask == REDRAW_NONE)
720 if (draw_mask & REDRAW_ALL)
723 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
726 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
729 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
732 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
738 boolean DrawingDeactivatedField(void)
740 if (program.headless)
743 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
749 boolean DrawingDeactivated(int x, int y, int width, int height)
751 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
754 boolean DrawingOnBackground(int x, int y)
756 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
757 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
760 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
761 int *width, int *height, boolean is_dest)
763 int clip_x, clip_y, clip_width, clip_height;
765 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
767 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
768 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
769 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
770 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
776 clip_width = bitmap->width;
777 clip_height = bitmap->height;
780 // skip if rectangle completely outside bitmap
782 if (*x + *width <= clip_x ||
783 *y + *height <= clip_y ||
784 *x >= clip_x + clip_width ||
785 *y >= clip_y + clip_height)
788 // clip if rectangle overlaps bitmap
792 *width -= clip_x - *x;
795 else if (*x + *width > clip_x + clip_width)
797 *width = clip_x + clip_width - *x;
802 *height -= clip_y - *y;
805 else if (*y + *height > clip_y + clip_height)
807 *height = clip_y + clip_height - *y;
813 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
814 int src_x, int src_y, int width, int height,
815 int dst_x, int dst_y)
817 int dst_x_unclipped = dst_x;
818 int dst_y_unclipped = dst_y;
820 if (program.headless)
823 if (src_bitmap == NULL || dst_bitmap == NULL)
826 if (DrawingDeactivated(dst_x, dst_y, width, height))
829 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
830 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
833 // source x/y might need adjustment if destination x/y was clipped top/left
834 src_x += dst_x - dst_x_unclipped;
835 src_y += dst_y - dst_y_unclipped;
837 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
838 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
839 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
840 but is already fixed in SVN and should therefore finally be fixed with
841 the next official SDL release, which is probably version 1.2.14.) */
842 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
844 if (src_bitmap == dst_bitmap)
846 // needed when blitting directly to same bitmap -- should not be needed with
847 // recent SDL libraries, but apparently does not work in 1.2.11 directly
849 static Bitmap *tmp_bitmap = NULL;
850 static int tmp_bitmap_xsize = 0;
851 static int tmp_bitmap_ysize = 0;
853 // start with largest static bitmaps for initial bitmap size ...
854 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
856 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
857 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
860 // ... and allow for later re-adjustments due to custom artwork bitmaps
861 if (src_bitmap->width > tmp_bitmap_xsize ||
862 src_bitmap->height > tmp_bitmap_ysize)
864 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
865 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
867 FreeBitmap(tmp_bitmap);
872 if (tmp_bitmap == NULL)
873 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
876 sysCopyArea(src_bitmap, tmp_bitmap,
877 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
878 sysCopyArea(tmp_bitmap, dst_bitmap,
879 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
884 sysCopyArea(src_bitmap, dst_bitmap,
885 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
888 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
889 int src_x, int src_y, int src_width, int src_height,
890 int dst_x, int dst_y, int dst_width, int dst_height)
892 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
893 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
894 int dst_xsize = dst_width;
895 int dst_ysize = dst_height;
896 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
897 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
900 for (y = 0; y < src_ysteps; y++)
902 for (x = 0; x < src_xsteps; x++)
904 int draw_x = dst_x + x * src_xsize;
905 int draw_y = dst_y + y * src_ysize;
906 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
907 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
909 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
915 void FadeRectangle(int x, int y, int width, int height,
916 int fade_mode, int fade_delay, int post_delay,
917 void (*draw_border_function)(void))
919 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
920 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
923 SDLFadeRectangle(x, y, width, height,
924 fade_mode, fade_delay, post_delay, draw_border_function);
927 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
930 if (DrawingDeactivated(x, y, width, height))
933 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
936 sysFillRectangle(bitmap, x, y, width, height, color);
939 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
941 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
944 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
945 int width, int height)
947 if (DrawingOnBackground(x, y))
948 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
950 ClearRectangle(bitmap, x, y, width, height);
953 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
954 int src_x, int src_y, int width, int height,
955 int dst_x, int dst_y)
957 if (DrawingDeactivated(dst_x, dst_y, width, height))
960 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
961 dst_x, dst_y, BLIT_MASKED);
964 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
965 int src_x, int src_y, int width, int height,
966 int dst_x, int dst_y)
968 if (DrawingOnBackground(dst_x, dst_y))
971 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
975 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
979 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
983 void BlitTexture(Bitmap *bitmap,
984 int src_x, int src_y, int width, int height,
985 int dst_x, int dst_y)
990 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
994 void BlitTextureMasked(Bitmap *bitmap,
995 int src_x, int src_y, int width, int height,
996 int dst_x, int dst_y)
1001 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1005 void BlitToScreen(Bitmap *bitmap,
1006 int src_x, int src_y, int width, int height,
1007 int dst_x, int dst_y)
1012 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1013 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1014 width, height, dst_x, dst_y);
1016 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1019 void BlitToScreenMasked(Bitmap *bitmap,
1020 int src_x, int src_y, int width, int height,
1021 int dst_x, int dst_y)
1026 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1027 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1028 width, height, dst_x, dst_y);
1030 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1033 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1036 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1039 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1042 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1045 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1046 int to_x, int to_y, Pixel pixel, int line_width)
1050 if (program.headless)
1053 for (x = 0; x < line_width; x++)
1055 for (y = 0; y < line_width; y++)
1057 int dx = x - line_width / 2;
1058 int dy = y - line_width / 2;
1060 if ((x == 0 && y == 0) ||
1061 (x == 0 && y == line_width - 1) ||
1062 (x == line_width - 1 && y == 0) ||
1063 (x == line_width - 1 && y == line_width - 1))
1067 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1072 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1077 for (i = 0; i < num_points - 1; i++)
1078 DrawLine(bitmap, points[i].x, points[i].y,
1079 points[i + 1].x, points[i + 1].y, pixel, line_width);
1082 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1086 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1088 if (program.headless)
1091 if (x < 0 || x >= bitmap->width ||
1092 y < 0 || y >= bitmap->height)
1095 return SDLGetPixel(bitmap, x, y);
1098 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1099 unsigned int color_g, unsigned int color_b)
1101 if (program.headless)
1104 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1107 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1109 unsigned int color_r = (color >> 16) & 0xff;
1110 unsigned int color_g = (color >> 8) & 0xff;
1111 unsigned int color_b = (color >> 0) & 0xff;
1113 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1116 void KeyboardAutoRepeatOn(void)
1118 keyrepeat_status = TRUE;
1121 void KeyboardAutoRepeatOff(void)
1123 keyrepeat_status = FALSE;
1126 boolean SetVideoMode(boolean fullscreen)
1128 return SDLSetVideoMode(fullscreen);
1131 void SetVideoFrameDelay(unsigned int frame_delay_value)
1133 video.frame_delay_value = frame_delay_value;
1136 unsigned int GetVideoFrameDelay(void)
1138 return video.frame_delay_value;
1141 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1143 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1144 (!fullscreen && video.fullscreen_enabled))
1145 fullscreen = SetVideoMode(fullscreen);
1150 Bitmap *LoadImage(char *filename)
1154 new_bitmap = SDLLoadImage(filename);
1157 new_bitmap->source_filename = getStringCopy(filename);
1162 Bitmap *LoadCustomImage(char *basename)
1164 char *filename = getCustomImageFilename(basename);
1167 if (filename == NULL)
1168 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1170 if ((new_bitmap = LoadImage(filename)) == NULL)
1171 Fail("LoadImage('%s') failed", basename);
1176 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1178 char *filename = getCustomImageFilename(basename);
1181 if (filename == NULL) // (should never happen)
1183 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1188 if (strEqual(filename, bitmap->source_filename))
1190 // The old and new image are the same (have the same filename and path).
1191 // This usually means that this image does not exist in this graphic set
1192 // and a fallback to the existing image is done.
1197 if ((new_bitmap = LoadImage(filename)) == NULL)
1199 Warn("LoadImage('%s') failed", basename);
1204 if (bitmap->width != new_bitmap->width ||
1205 bitmap->height != new_bitmap->height)
1207 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1210 FreeBitmap(new_bitmap);
1215 TransferBitmapPointers(new_bitmap, bitmap);
1219 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1221 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1224 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1226 if (bitmaps[IMG_BITMAP_CUSTOM])
1228 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1230 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1233 if (gfx.game_tile_size == gfx.standard_tile_size)
1235 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1240 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1241 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1242 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1244 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1246 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1247 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1250 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1251 int tile_size, boolean create_small_bitmaps)
1253 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1254 Bitmap *tmp_bitmap_final = NULL;
1255 Bitmap *tmp_bitmap_0 = NULL;
1256 Bitmap *tmp_bitmap_1 = NULL;
1257 Bitmap *tmp_bitmap_2 = NULL;
1258 Bitmap *tmp_bitmap_4 = NULL;
1259 Bitmap *tmp_bitmap_8 = NULL;
1260 Bitmap *tmp_bitmap_16 = NULL;
1261 Bitmap *tmp_bitmap_32 = NULL;
1262 int width_final, height_final;
1263 int width_0, height_0;
1264 int width_1, height_1;
1265 int width_2, height_2;
1266 int width_4, height_4;
1267 int width_8, height_8;
1268 int width_16, height_16;
1269 int width_32, height_32;
1270 int old_width, old_height;
1273 print_timestamp_init("CreateScaledBitmaps");
1275 old_width = old_bitmap->width;
1276 old_height = old_bitmap->height;
1278 // calculate new image dimensions for final image size
1279 width_final = old_width * zoom_factor;
1280 height_final = old_height * zoom_factor;
1282 // get image with final size (this might require scaling up)
1283 // ("final" size may result in non-standard tile size image)
1284 if (zoom_factor != 1)
1285 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1287 tmp_bitmap_final = old_bitmap;
1289 UPDATE_BUSY_STATE();
1291 width_0 = width_1 = width_final;
1292 height_0 = height_1 = height_final;
1294 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1296 if (create_small_bitmaps)
1298 // check if we have a non-gameplay tile size image
1299 if (tile_size != gfx.game_tile_size)
1301 // get image with gameplay tile size
1302 width_0 = width_final * gfx.game_tile_size / tile_size;
1303 height_0 = height_final * gfx.game_tile_size / tile_size;
1305 if (width_0 == old_width)
1306 tmp_bitmap_0 = old_bitmap;
1307 else if (width_0 == width_final)
1308 tmp_bitmap_0 = tmp_bitmap_final;
1310 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1312 UPDATE_BUSY_STATE();
1315 // check if we have a non-standard tile size image
1316 if (tile_size != gfx.standard_tile_size)
1318 // get image with standard tile size
1319 width_1 = width_final * gfx.standard_tile_size / tile_size;
1320 height_1 = height_final * gfx.standard_tile_size / tile_size;
1322 if (width_1 == old_width)
1323 tmp_bitmap_1 = old_bitmap;
1324 else if (width_1 == width_final)
1325 tmp_bitmap_1 = tmp_bitmap_final;
1326 else if (width_1 == width_0)
1327 tmp_bitmap_1 = tmp_bitmap_0;
1329 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1331 UPDATE_BUSY_STATE();
1334 // calculate new image dimensions for small images
1335 width_2 = width_1 / 2;
1336 height_2 = height_1 / 2;
1337 width_4 = width_1 / 4;
1338 height_4 = height_1 / 4;
1339 width_8 = width_1 / 8;
1340 height_8 = height_1 / 8;
1341 width_16 = width_1 / 16;
1342 height_16 = height_1 / 16;
1343 width_32 = width_1 / 32;
1344 height_32 = height_1 / 32;
1346 // get image with 1/2 of normal size (for use in the level editor)
1347 if (width_2 == old_width)
1348 tmp_bitmap_2 = old_bitmap;
1350 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1352 UPDATE_BUSY_STATE();
1354 // get image with 1/4 of normal size (for use in the level editor)
1355 if (width_4 == old_width)
1356 tmp_bitmap_4 = old_bitmap;
1358 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1360 UPDATE_BUSY_STATE();
1362 // get image with 1/8 of normal size (for use on the preview screen)
1363 if (width_8 == old_width)
1364 tmp_bitmap_8 = old_bitmap;
1366 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1368 UPDATE_BUSY_STATE();
1370 // get image with 1/16 of normal size (for use on the preview screen)
1371 if (width_16 == old_width)
1372 tmp_bitmap_16 = old_bitmap;
1374 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1376 UPDATE_BUSY_STATE();
1378 // get image with 1/32 of normal size (for use on the preview screen)
1379 if (width_32 == old_width)
1380 tmp_bitmap_32 = old_bitmap;
1382 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1384 UPDATE_BUSY_STATE();
1386 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1387 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1388 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1389 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1390 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1391 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1393 if (width_0 != width_1)
1394 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1396 if (bitmaps[IMG_BITMAP_CUSTOM])
1397 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1399 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1401 boolean free_old_bitmap = TRUE;
1403 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1404 if (bitmaps[i] == old_bitmap)
1405 free_old_bitmap = FALSE;
1407 if (free_old_bitmap)
1409 // copy image filename from old to new standard sized bitmap
1410 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1411 getStringCopy(old_bitmap->source_filename);
1413 FreeBitmap(old_bitmap);
1418 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1421 UPDATE_BUSY_STATE();
1423 print_timestamp_done("CreateScaledBitmaps");
1426 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1429 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1432 void CreateBitmapTextures(Bitmap **bitmaps)
1434 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1437 void FreeBitmapTextures(Bitmap **bitmaps)
1439 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1442 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1444 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1448 // ----------------------------------------------------------------------------
1449 // mouse pointer functions
1450 // ----------------------------------------------------------------------------
1452 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1454 // XPM image definitions
1455 static const char *cursor_image_none[] =
1457 // width height num_colors chars_per_pixel
1487 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1488 static const char *cursor_image_dot[] =
1490 // width height num_colors chars_per_pixel
1519 static const char **cursor_image_playfield = cursor_image_dot;
1521 // some people complained about a "white dot" on the screen and thought it
1522 // was a graphical error... OK, let's just remove the whole pointer :-)
1523 static const char **cursor_image_playfield = cursor_image_none;
1526 static const int cursor_bit_order = BIT_ORDER_MSB;
1528 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1530 struct MouseCursorInfo *cursor;
1531 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1532 int header_lines = 4;
1535 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1537 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1540 for (y = 0; y < cursor->width; y++)
1542 for (x = 0; x < cursor->height; x++)
1545 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1550 cursor->data[i] = cursor->mask[i] = 0;
1553 switch (image[header_lines + y][x])
1556 cursor->data[i] |= bit_mask;
1557 cursor->mask[i] |= bit_mask;
1561 cursor->mask[i] |= bit_mask;
1570 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1575 void SetMouseCursor(int mode)
1577 static struct MouseCursorInfo *cursor_none = NULL;
1578 static struct MouseCursorInfo *cursor_playfield = NULL;
1579 struct MouseCursorInfo *cursor_new;
1580 int mode_final = mode;
1582 if (cursor_none == NULL)
1583 cursor_none = get_cursor_from_image(cursor_image_none);
1585 if (cursor_playfield == NULL)
1586 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1588 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1589 mode_final = gfx.cursor_mode_override;
1591 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1592 mode_final == CURSOR_NONE ? cursor_none :
1593 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1595 SDLSetMouseCursor(cursor_new);
1597 gfx.cursor_mode = mode;
1598 gfx.cursor_mode_final = mode_final;
1601 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1603 // mouse events do not contain logical screen size corrections yet
1604 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1606 mouse_x -= video.screen_xoffset;
1607 mouse_y -= video.screen_yoffset;
1609 gfx.mouse_x = mouse_x;
1610 gfx.mouse_y = mouse_y;
1613 void UpdateMousePosition(void)
1615 int mouse_x, mouse_y;
1618 SDL_GetMouseState(&mouse_x, &mouse_y);
1620 UpdateRawMousePosition(mouse_x, mouse_y);
1624 // ============================================================================
1626 // ============================================================================
1628 void OpenAudio(void)
1630 // always start with reliable default values
1631 audio.sound_available = FALSE;
1632 audio.music_available = FALSE;
1633 audio.loops_available = FALSE;
1635 audio.sound_enabled = FALSE;
1636 audio.sound_deactivated = FALSE;
1638 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1639 audio.mixer_pid = 0;
1640 audio.device_name = NULL;
1641 audio.device_fd = -1;
1643 audio.num_channels = 0;
1644 audio.music_channel = 0;
1645 audio.first_sound_channel = 0;
1650 void CloseAudio(void)
1654 audio.sound_enabled = FALSE;
1657 void SetAudioMode(boolean enabled)
1659 if (!audio.sound_available)
1662 audio.sound_enabled = enabled;
1666 // ============================================================================
1668 // ============================================================================
1670 void InitEventFilter(EventFilter filter_function)
1672 SDL_SetEventFilter(filter_function, NULL);
1675 boolean PendingEvent(void)
1677 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1680 void WaitEvent(Event *event)
1682 SDLWaitEvent(event);
1685 void PeekEvent(Event *event)
1687 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1690 void PumpEvents(void)
1695 void CheckQuitEvent(void)
1697 if (SDL_QuitRequested())
1698 program.exit_function(0);
1701 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1703 // key up/down events in SDL2 do not return text characters anymore
1704 return event->keysym.sym;
1707 KeyMod HandleKeyModState(Key key, int key_status)
1709 static KeyMod current_modifiers = KMOD_None;
1711 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1713 KeyMod new_modifier = KMOD_None;
1718 new_modifier = KMOD_Shift_L;
1721 new_modifier = KMOD_Shift_R;
1723 case KSYM_Control_L:
1724 new_modifier = KMOD_Control_L;
1726 case KSYM_Control_R:
1727 new_modifier = KMOD_Control_R;
1730 new_modifier = KMOD_Meta_L;
1733 new_modifier = KMOD_Meta_R;
1736 new_modifier = KMOD_Alt_L;
1739 new_modifier = KMOD_Alt_R;
1745 if (key_status == KEY_PRESSED)
1746 current_modifiers |= new_modifier;
1748 current_modifiers &= ~new_modifier;
1751 return current_modifiers;
1754 KeyMod GetKeyModState(void)
1756 return (KeyMod)SDL_GetModState();
1759 KeyMod GetKeyModStateFromEvents(void)
1761 /* always use key modifier state as tracked from key events (this is needed
1762 if the modifier key event was injected into the event queue, but the key
1763 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1764 query the keys as held pressed on the keyboard) -- this case is currently
1765 only used to filter out clipboard insert events from "True X-Mouse" tool */
1767 return HandleKeyModState(KSYM_UNDEFINED, 0);
1770 void StartTextInput(int x, int y, int width, int height)
1772 textinput_status = TRUE;
1774 #if defined(HAS_SCREEN_KEYBOARD)
1775 SDL_StartTextInput();
1777 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1779 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1780 video.shifted_up_delay = SDL_GetTicks();
1781 video.shifted_up = TRUE;
1786 void StopTextInput(void)
1788 textinput_status = FALSE;
1790 #if defined(HAS_SCREEN_KEYBOARD)
1791 SDL_StopTextInput();
1793 if (video.shifted_up)
1795 video.shifted_up_pos = 0;
1796 video.shifted_up_delay = SDL_GetTicks();
1797 video.shifted_up = FALSE;
1802 void PushUserEvent(int code, int value1, int value2)
1806 SDL_memset(&event, 0, sizeof(event));
1808 event.type = EVENT_USER;
1810 event.value1 = value1;
1811 event.value2 = value2;
1813 SDL_PushEvent((SDL_Event *)&event);
1817 // ============================================================================
1818 // joystick functions
1819 // ============================================================================
1821 void InitJoysticks(void)
1825 #if defined(NO_JOYSTICK)
1826 return; // joysticks generally deactivated by compile-time directive
1829 // always start with reliable default values
1830 joystick.status = JOYSTICK_NOT_AVAILABLE;
1831 for (i = 0; i < MAX_PLAYERS; i++)
1832 joystick.nr[i] = -1; // no joystick configured
1837 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1839 return SDLReadJoystick(nr, x, y, b1, b2);
1842 boolean CheckJoystickOpened(int nr)
1844 return SDLCheckJoystickOpened(nr);
1847 void ClearJoystickState(void)
1849 SDLClearJoystickState();