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;
353 void InitOverlayInfo(void)
355 overlay.enabled = FALSE;
356 overlay.active = FALSE;
358 overlay.show_grid = FALSE;
360 overlay.grid_button_highlight = CHAR_GRID_BUTTON_NONE;
361 overlay.grid_button_action = JOY_NO_ACTION;
363 SetOverlayGridSizeAndButtons();
365 #if defined(USE_TOUCH_INPUT_OVERLAY)
366 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
367 overlay.enabled = TRUE;
371 void SetOverlayGridSizeAndButtons(void)
373 int nr = GRID_ACTIVE_NR();
376 overlay.grid_xsize = setup.touch.grid_xsize[nr];
377 overlay.grid_ysize = setup.touch.grid_ysize[nr];
379 for (x = 0; x < MAX_GRID_XSIZE; x++)
380 for (y = 0; y < MAX_GRID_YSIZE; y++)
381 overlay.grid_button[x][y] = setup.touch.grid_button[nr][x][y];
384 void SetTileCursorEnabled(boolean enabled)
386 tile_cursor.enabled = enabled;
389 void SetTileCursorActive(boolean active)
391 tile_cursor.active = active;
394 void SetTileCursorTargetXY(int x, int y)
396 // delayed placement of tile selection cursor at target position
397 // (tile cursor will be moved to target position step by step)
399 tile_cursor.xpos = x;
400 tile_cursor.ypos = y;
401 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
402 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
404 tile_cursor.moving = TRUE;
407 void SetTileCursorXY(int x, int y)
409 // immediate placement of tile selection cursor at target position
411 SetTileCursorTargetXY(x, y);
413 tile_cursor.x = tile_cursor.target_x;
414 tile_cursor.y = tile_cursor.target_y;
416 tile_cursor.moving = FALSE;
419 void SetTileCursorSXSY(int sx, int sy)
425 void SetOverlayEnabled(boolean enabled)
427 overlay.enabled = enabled;
430 void SetOverlayActive(boolean active)
432 overlay.active = active;
435 void SetOverlayShowGrid(boolean show_grid)
437 overlay.show_grid = show_grid;
439 SetOverlayActive(show_grid);
442 SetOverlayEnabled(TRUE);
445 boolean GetOverlayEnabled(void)
447 return overlay.enabled;
450 boolean GetOverlayActive(void)
452 return overlay.active;
455 void SetDrawDeactivationMask(int draw_deactivation_mask)
457 gfx.draw_deactivation_mask = draw_deactivation_mask;
460 int GetDrawDeactivationMask(void)
462 return gfx.draw_deactivation_mask;
465 void SetDrawBackgroundMask(int draw_background_mask)
467 gfx.draw_background_mask = draw_background_mask;
470 static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
472 if (background_bitmap_tile != NULL)
473 gfx.background_bitmap_mask |= mask;
475 gfx.background_bitmap_mask &= ~mask;
477 if (background_bitmap_tile == NULL) // empty background requested
480 if (mask == REDRAW_ALL)
481 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
482 0, 0, video.width, video.height);
483 else if (mask == REDRAW_FIELD)
484 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
485 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
486 else if (mask == REDRAW_DOOR_1)
487 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
488 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
491 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
493 // remove every mask before setting mask for window
494 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
495 SetBackgroundBitmap(NULL, 0xffff); // !!! FIX THIS !!!
496 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
499 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
501 // remove window area mask before setting mask for main area
502 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
503 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
504 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
507 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
509 // remove window area mask before setting mask for door area
510 // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
511 SetBackgroundBitmap(NULL, REDRAW_ALL); // !!! FIX THIS !!!
512 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
516 // ============================================================================
518 // ============================================================================
520 static int GetRealDepth(int depth)
522 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
525 static void sysFillRectangle(Bitmap *bitmap, int x, int y,
526 int width, int height, Pixel color)
528 SDLFillRectangle(bitmap, x, y, width, height, color);
530 if (bitmap == backbuffer)
531 SetRedrawMaskFromArea(x, y, width, height);
534 static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
535 int src_x, int src_y, int width, int height,
536 int dst_x, int dst_y, int mask_mode)
538 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
539 dst_x, dst_y, mask_mode);
541 if (dst_bitmap == backbuffer)
542 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
545 void LimitScreenUpdates(boolean enable)
547 SDLLimitScreenUpdates(enable);
550 void InitVideoDefaults(void)
552 video.default_depth = 32;
555 void InitVideoDisplay(void)
557 if (program.headless)
560 SDLInitVideoDisplay();
564 void CloseVideoDisplay(void)
566 KeyboardAutoRepeatOn();
568 SDL_QuitSubSystem(SDL_INIT_VIDEO);
571 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
574 video.height = height;
575 video.depth = GetRealDepth(depth);
577 video.screen_width = width;
578 video.screen_height = height;
579 video.screen_xoffset = 0;
580 video.screen_yoffset = 0;
582 video.fullscreen_available = FULLSCREEN_STATUS;
583 video.fullscreen_enabled = FALSE;
585 video.window_scaling_available = WINDOW_SCALING_STATUS;
587 video.frame_counter = 0;
588 video.frame_delay = 0;
589 video.frame_delay_value = GAME_FRAME_DELAY;
591 video.shifted_up = FALSE;
592 video.shifted_up_pos = 0;
593 video.shifted_up_pos_last = 0;
594 video.shifted_up_delay = 0;
595 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
597 SDLInitVideoBuffer(fullscreen);
599 video.initialized = !program.headless;
604 static void FreeBitmapPointers(Bitmap *bitmap)
609 SDLFreeBitmapPointers(bitmap);
611 checked_free(bitmap->source_filename);
612 bitmap->source_filename = NULL;
615 static void TransferBitmapPointers(Bitmap *src_bitmap,
618 if (src_bitmap == NULL || dst_bitmap == NULL)
621 FreeBitmapPointers(dst_bitmap);
623 *dst_bitmap = *src_bitmap;
626 void FreeBitmap(Bitmap *bitmap)
631 FreeBitmapPointers(bitmap);
636 Bitmap *CreateBitmapStruct(void)
638 return checked_calloc(sizeof(Bitmap));
641 Bitmap *CreateBitmap(int width, int height, int depth)
643 Bitmap *new_bitmap = CreateBitmapStruct();
644 int real_width = MAX(1, width); // prevent zero bitmap width
645 int real_height = MAX(1, height); // prevent zero bitmap height
646 int real_depth = GetRealDepth(depth);
648 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
650 new_bitmap->width = real_width;
651 new_bitmap->height = real_height;
656 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
660 // if new bitmap size fits into old one, no need to re-create it
661 if (width <= (*bitmap)->width &&
662 height <= (*bitmap)->height)
665 // else adjust size so that old and new bitmap size fit into it
666 width = MAX(width, (*bitmap)->width);
667 height = MAX(height, (*bitmap)->height);
670 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
674 *bitmap = new_bitmap;
678 TransferBitmapPointers(new_bitmap, *bitmap);
684 static void CloseWindow(DrawWindow *window)
689 void SetRedrawMaskFromArea(int x, int y, int width, int height)
693 int x2 = x + width - 1;
694 int y2 = y + height - 1;
696 if (width == 0 || height == 0)
699 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
700 redraw_mask |= REDRAW_FIELD;
701 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
702 redraw_mask |= REDRAW_DOOR_1;
703 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
704 redraw_mask |= REDRAW_DOOR_2;
705 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
706 redraw_mask |= REDRAW_DOOR_3;
708 redraw_mask = REDRAW_ALL;
711 static boolean CheckDrawingArea(int x, int y, int width, int height,
714 if (draw_mask == REDRAW_NONE)
717 if (draw_mask & REDRAW_ALL)
720 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
723 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
726 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
729 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
735 boolean DrawingDeactivatedField(void)
737 if (program.headless)
740 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
746 boolean DrawingDeactivated(int x, int y, int width, int height)
748 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
751 boolean DrawingOnBackground(int x, int y)
753 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
754 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
757 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
758 int *width, int *height, boolean is_dest)
760 int clip_x, clip_y, clip_width, clip_height;
762 if (gfx.clipping_enabled && is_dest) // only clip destination bitmap
764 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
765 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
766 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
767 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
773 clip_width = bitmap->width;
774 clip_height = bitmap->height;
777 // skip if rectangle completely outside bitmap
779 if (*x + *width <= clip_x ||
780 *y + *height <= clip_y ||
781 *x >= clip_x + clip_width ||
782 *y >= clip_y + clip_height)
785 // clip if rectangle overlaps bitmap
789 *width -= clip_x - *x;
792 else if (*x + *width > clip_x + clip_width)
794 *width = clip_x + clip_width - *x;
799 *height -= clip_y - *y;
802 else if (*y + *height > clip_y + clip_height)
804 *height = clip_y + clip_height - *y;
810 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
811 int src_x, int src_y, int width, int height,
812 int dst_x, int dst_y)
814 int dst_x_unclipped = dst_x;
815 int dst_y_unclipped = dst_y;
817 if (program.headless)
820 if (src_bitmap == NULL || dst_bitmap == NULL)
823 if (DrawingDeactivated(dst_x, dst_y, width, height))
826 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
827 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
830 // source x/y might need adjustment if destination x/y was clipped top/left
831 src_x += dst_x - dst_x_unclipped;
832 src_y += dst_y - dst_y_unclipped;
834 // !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!!
835 // !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!!
836 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
837 but is already fixed in SVN and should therefore finally be fixed with
838 the next official SDL release, which is probably version 1.2.14.) */
839 // !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!!
841 if (src_bitmap == dst_bitmap)
843 // needed when blitting directly to same bitmap -- should not be needed with
844 // recent SDL libraries, but apparently does not work in 1.2.11 directly
846 static Bitmap *tmp_bitmap = NULL;
847 static int tmp_bitmap_xsize = 0;
848 static int tmp_bitmap_ysize = 0;
850 // start with largest static bitmaps for initial bitmap size ...
851 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
853 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
854 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
857 // ... and allow for later re-adjustments due to custom artwork bitmaps
858 if (src_bitmap->width > tmp_bitmap_xsize ||
859 src_bitmap->height > tmp_bitmap_ysize)
861 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
862 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
864 FreeBitmap(tmp_bitmap);
869 if (tmp_bitmap == NULL)
870 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
873 sysCopyArea(src_bitmap, tmp_bitmap,
874 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
875 sysCopyArea(tmp_bitmap, dst_bitmap,
876 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
881 sysCopyArea(src_bitmap, dst_bitmap,
882 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
885 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
886 int src_x, int src_y, int src_width, int src_height,
887 int dst_x, int dst_y, int dst_width, int dst_height)
889 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
890 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
891 int dst_xsize = dst_width;
892 int dst_ysize = dst_height;
893 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
894 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
897 for (y = 0; y < src_ysteps; y++)
899 for (x = 0; x < src_xsteps; x++)
901 int draw_x = dst_x + x * src_xsize;
902 int draw_y = dst_y + y * src_ysize;
903 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
904 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
906 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
912 void FadeRectangle(int x, int y, int width, int height,
913 int fade_mode, int fade_delay, int post_delay,
914 void (*draw_border_function)(void))
916 // (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined)
917 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
920 SDLFadeRectangle(x, y, width, height,
921 fade_mode, fade_delay, post_delay, draw_border_function);
924 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
927 if (DrawingDeactivated(x, y, width, height))
930 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
933 sysFillRectangle(bitmap, x, y, width, height, color);
936 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
938 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
941 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
942 int width, int height)
944 if (DrawingOnBackground(x, y))
945 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
947 ClearRectangle(bitmap, x, y, width, height);
950 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
951 int src_x, int src_y, int width, int height,
952 int dst_x, int dst_y)
954 if (DrawingDeactivated(dst_x, dst_y, width, height))
957 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
958 dst_x, dst_y, BLIT_MASKED);
961 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
962 int src_x, int src_y, int width, int height,
963 int dst_x, int dst_y)
965 if (DrawingOnBackground(dst_x, dst_y))
968 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
972 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
976 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
980 void BlitTexture(Bitmap *bitmap,
981 int src_x, int src_y, int width, int height,
982 int dst_x, int dst_y)
987 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
991 void BlitTextureMasked(Bitmap *bitmap,
992 int src_x, int src_y, int width, int height,
993 int dst_x, int dst_y)
998 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
1002 void BlitToScreen(Bitmap *bitmap,
1003 int src_x, int src_y, int width, int height,
1004 int dst_x, int dst_y)
1009 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1010 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1011 width, height, dst_x, dst_y);
1013 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1016 void BlitToScreenMasked(Bitmap *bitmap,
1017 int src_x, int src_y, int width, int height,
1018 int dst_x, int dst_y)
1023 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
1024 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
1025 width, height, dst_x, dst_y);
1027 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
1030 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
1033 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
1036 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
1039 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
1042 static void DrawLine(Bitmap *bitmap, int from_x, int from_y,
1043 int to_x, int to_y, Pixel pixel, int line_width)
1047 if (program.headless)
1050 for (x = 0; x < line_width; x++)
1052 for (y = 0; y < line_width; y++)
1054 int dx = x - line_width / 2;
1055 int dy = y - line_width / 2;
1057 if ((x == 0 && y == 0) ||
1058 (x == 0 && y == line_width - 1) ||
1059 (x == line_width - 1 && y == 0) ||
1060 (x == line_width - 1 && y == line_width - 1))
1064 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1069 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1074 for (i = 0; i < num_points - 1; i++)
1075 DrawLine(bitmap, points[i].x, points[i].y,
1076 points[i + 1].x, points[i + 1].y, pixel, line_width);
1079 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1083 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1085 if (program.headless)
1088 if (x < 0 || x >= bitmap->width ||
1089 y < 0 || y >= bitmap->height)
1092 return SDLGetPixel(bitmap, x, y);
1095 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1096 unsigned int color_g, unsigned int color_b)
1098 if (program.headless)
1101 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1104 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1106 unsigned int color_r = (color >> 16) & 0xff;
1107 unsigned int color_g = (color >> 8) & 0xff;
1108 unsigned int color_b = (color >> 0) & 0xff;
1110 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1113 void KeyboardAutoRepeatOn(void)
1115 keyrepeat_status = TRUE;
1118 void KeyboardAutoRepeatOff(void)
1120 keyrepeat_status = FALSE;
1123 boolean SetVideoMode(boolean fullscreen)
1125 return SDLSetVideoMode(fullscreen);
1128 void SetVideoFrameDelay(unsigned int frame_delay_value)
1130 video.frame_delay_value = frame_delay_value;
1133 unsigned int GetVideoFrameDelay(void)
1135 return video.frame_delay_value;
1138 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1140 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1141 (!fullscreen && video.fullscreen_enabled))
1142 fullscreen = SetVideoMode(fullscreen);
1147 Bitmap *LoadImage(char *filename)
1151 new_bitmap = SDLLoadImage(filename);
1154 new_bitmap->source_filename = getStringCopy(filename);
1159 Bitmap *LoadCustomImage(char *basename)
1161 char *filename = getCustomImageFilename(basename);
1164 if (filename == NULL)
1165 Fail("LoadCustomImage(): cannot find file '%s'", basename);
1167 if ((new_bitmap = LoadImage(filename)) == NULL)
1168 Fail("LoadImage('%s') failed", basename);
1173 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1175 char *filename = getCustomImageFilename(basename);
1178 if (filename == NULL) // (should never happen)
1180 Warn("ReloadCustomImage(): cannot find file '%s'", basename);
1185 if (strEqual(filename, bitmap->source_filename))
1187 // The old and new image are the same (have the same filename and path).
1188 // This usually means that this image does not exist in this graphic set
1189 // and a fallback to the existing image is done.
1194 if ((new_bitmap = LoadImage(filename)) == NULL)
1196 Warn("LoadImage('%s') failed", basename);
1201 if (bitmap->width != new_bitmap->width ||
1202 bitmap->height != new_bitmap->height)
1204 Warn("ReloadCustomImage: new image '%s' has wrong dimensions",
1207 FreeBitmap(new_bitmap);
1212 TransferBitmapPointers(new_bitmap, bitmap);
1216 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1218 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1221 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1223 if (bitmaps[IMG_BITMAP_CUSTOM])
1225 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1227 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1230 if (gfx.game_tile_size == gfx.standard_tile_size)
1232 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1237 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1238 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1239 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1241 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1243 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1244 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1247 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1248 int tile_size, boolean create_small_bitmaps)
1250 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1251 Bitmap *tmp_bitmap_final = NULL;
1252 Bitmap *tmp_bitmap_0 = NULL;
1253 Bitmap *tmp_bitmap_1 = NULL;
1254 Bitmap *tmp_bitmap_2 = NULL;
1255 Bitmap *tmp_bitmap_4 = NULL;
1256 Bitmap *tmp_bitmap_8 = NULL;
1257 Bitmap *tmp_bitmap_16 = NULL;
1258 Bitmap *tmp_bitmap_32 = NULL;
1259 int width_final, height_final;
1260 int width_0, height_0;
1261 int width_1, height_1;
1262 int width_2, height_2;
1263 int width_4, height_4;
1264 int width_8, height_8;
1265 int width_16, height_16;
1266 int width_32, height_32;
1267 int old_width, old_height;
1270 print_timestamp_init("CreateScaledBitmaps");
1272 old_width = old_bitmap->width;
1273 old_height = old_bitmap->height;
1275 // calculate new image dimensions for final image size
1276 width_final = old_width * zoom_factor;
1277 height_final = old_height * zoom_factor;
1279 // get image with final size (this might require scaling up)
1280 // ("final" size may result in non-standard tile size image)
1281 if (zoom_factor != 1)
1282 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1284 tmp_bitmap_final = old_bitmap;
1286 UPDATE_BUSY_STATE();
1288 width_0 = width_1 = width_final;
1289 height_0 = height_1 = height_final;
1291 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1293 if (create_small_bitmaps)
1295 // check if we have a non-gameplay tile size image
1296 if (tile_size != gfx.game_tile_size)
1298 // get image with gameplay tile size
1299 width_0 = width_final * gfx.game_tile_size / tile_size;
1300 height_0 = height_final * gfx.game_tile_size / tile_size;
1302 if (width_0 == old_width)
1303 tmp_bitmap_0 = old_bitmap;
1304 else if (width_0 == width_final)
1305 tmp_bitmap_0 = tmp_bitmap_final;
1307 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1309 UPDATE_BUSY_STATE();
1312 // check if we have a non-standard tile size image
1313 if (tile_size != gfx.standard_tile_size)
1315 // get image with standard tile size
1316 width_1 = width_final * gfx.standard_tile_size / tile_size;
1317 height_1 = height_final * gfx.standard_tile_size / tile_size;
1319 if (width_1 == old_width)
1320 tmp_bitmap_1 = old_bitmap;
1321 else if (width_1 == width_final)
1322 tmp_bitmap_1 = tmp_bitmap_final;
1323 else if (width_1 == width_0)
1324 tmp_bitmap_1 = tmp_bitmap_0;
1326 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1328 UPDATE_BUSY_STATE();
1331 // calculate new image dimensions for small images
1332 width_2 = width_1 / 2;
1333 height_2 = height_1 / 2;
1334 width_4 = width_1 / 4;
1335 height_4 = height_1 / 4;
1336 width_8 = width_1 / 8;
1337 height_8 = height_1 / 8;
1338 width_16 = width_1 / 16;
1339 height_16 = height_1 / 16;
1340 width_32 = width_1 / 32;
1341 height_32 = height_1 / 32;
1343 // get image with 1/2 of normal size (for use in the level editor)
1344 if (width_2 == old_width)
1345 tmp_bitmap_2 = old_bitmap;
1347 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1349 UPDATE_BUSY_STATE();
1351 // get image with 1/4 of normal size (for use in the level editor)
1352 if (width_4 == old_width)
1353 tmp_bitmap_4 = old_bitmap;
1355 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1357 UPDATE_BUSY_STATE();
1359 // get image with 1/8 of normal size (for use on the preview screen)
1360 if (width_8 == old_width)
1361 tmp_bitmap_8 = old_bitmap;
1363 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1365 UPDATE_BUSY_STATE();
1367 // get image with 1/16 of normal size (for use on the preview screen)
1368 if (width_16 == old_width)
1369 tmp_bitmap_16 = old_bitmap;
1371 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1373 UPDATE_BUSY_STATE();
1375 // get image with 1/32 of normal size (for use on the preview screen)
1376 if (width_32 == old_width)
1377 tmp_bitmap_32 = old_bitmap;
1379 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1381 UPDATE_BUSY_STATE();
1383 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1384 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1385 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1386 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1387 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1388 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1390 if (width_0 != width_1)
1391 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1393 if (bitmaps[IMG_BITMAP_CUSTOM])
1394 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1396 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1398 boolean free_old_bitmap = TRUE;
1400 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1401 if (bitmaps[i] == old_bitmap)
1402 free_old_bitmap = FALSE;
1404 if (free_old_bitmap)
1406 // copy image filename from old to new standard sized bitmap
1407 bitmaps[IMG_BITMAP_STANDARD]->source_filename =
1408 getStringCopy(old_bitmap->source_filename);
1410 FreeBitmap(old_bitmap);
1415 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1418 UPDATE_BUSY_STATE();
1420 print_timestamp_done("CreateScaledBitmaps");
1423 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1426 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1429 void CreateBitmapTextures(Bitmap **bitmaps)
1431 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1434 void FreeBitmapTextures(Bitmap **bitmaps)
1436 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1439 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1441 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1445 // ----------------------------------------------------------------------------
1446 // mouse pointer functions
1447 // ----------------------------------------------------------------------------
1449 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1451 // XPM image definitions
1452 static const char *cursor_image_none[] =
1454 // width height num_colors chars_per_pixel
1484 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1485 static const char *cursor_image_dot[] =
1487 // width height num_colors chars_per_pixel
1516 static const char **cursor_image_playfield = cursor_image_dot;
1518 // some people complained about a "white dot" on the screen and thought it
1519 // was a graphical error... OK, let's just remove the whole pointer :-)
1520 static const char **cursor_image_playfield = cursor_image_none;
1523 static const int cursor_bit_order = BIT_ORDER_MSB;
1525 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1527 struct MouseCursorInfo *cursor;
1528 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1529 int header_lines = 4;
1532 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1534 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1537 for (y = 0; y < cursor->width; y++)
1539 for (x = 0; x < cursor->height; x++)
1542 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1547 cursor->data[i] = cursor->mask[i] = 0;
1550 switch (image[header_lines + y][x])
1553 cursor->data[i] |= bit_mask;
1554 cursor->mask[i] |= bit_mask;
1558 cursor->mask[i] |= bit_mask;
1567 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1572 void SetMouseCursor(int mode)
1574 static struct MouseCursorInfo *cursor_none = NULL;
1575 static struct MouseCursorInfo *cursor_playfield = NULL;
1576 struct MouseCursorInfo *cursor_new;
1577 int mode_final = mode;
1579 if (cursor_none == NULL)
1580 cursor_none = get_cursor_from_image(cursor_image_none);
1582 if (cursor_playfield == NULL)
1583 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1585 if (gfx.cursor_mode_override != CURSOR_UNDEFINED)
1586 mode_final = gfx.cursor_mode_override;
1588 cursor_new = (mode_final == CURSOR_DEFAULT ? NULL :
1589 mode_final == CURSOR_NONE ? cursor_none :
1590 mode_final == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1592 SDLSetMouseCursor(cursor_new);
1594 gfx.cursor_mode = mode;
1595 gfx.cursor_mode_final = mode_final;
1598 void UpdateRawMousePosition(int mouse_x, int mouse_y)
1600 // mouse events do not contain logical screen size corrections yet
1601 SDLCorrectRawMousePosition(&mouse_x, &mouse_y);
1603 mouse_x -= video.screen_xoffset;
1604 mouse_y -= video.screen_yoffset;
1606 gfx.mouse_x = mouse_x;
1607 gfx.mouse_y = mouse_y;
1610 void UpdateMousePosition(void)
1612 int mouse_x, mouse_y;
1615 SDL_GetMouseState(&mouse_x, &mouse_y);
1617 UpdateRawMousePosition(mouse_x, mouse_y);
1621 // ============================================================================
1623 // ============================================================================
1625 void OpenAudio(void)
1627 // always start with reliable default values
1628 audio.sound_available = FALSE;
1629 audio.music_available = FALSE;
1630 audio.loops_available = FALSE;
1632 audio.sound_enabled = FALSE;
1633 audio.sound_deactivated = FALSE;
1635 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1636 audio.mixer_pid = 0;
1637 audio.device_name = NULL;
1638 audio.device_fd = -1;
1640 audio.num_channels = 0;
1641 audio.music_channel = 0;
1642 audio.first_sound_channel = 0;
1647 void CloseAudio(void)
1651 audio.sound_enabled = FALSE;
1654 void SetAudioMode(boolean enabled)
1656 if (!audio.sound_available)
1659 audio.sound_enabled = enabled;
1663 // ============================================================================
1665 // ============================================================================
1667 void InitEventFilter(EventFilter filter_function)
1669 SDL_SetEventFilter(filter_function, NULL);
1672 boolean PendingEvent(void)
1674 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1677 void WaitEvent(Event *event)
1679 SDLWaitEvent(event);
1682 void PeekEvent(Event *event)
1684 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1687 void PumpEvents(void)
1692 void CheckQuitEvent(void)
1694 if (SDL_QuitRequested())
1695 program.exit_function(0);
1698 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1700 // key up/down events in SDL2 do not return text characters anymore
1701 return event->keysym.sym;
1704 KeyMod HandleKeyModState(Key key, int key_status)
1706 static KeyMod current_modifiers = KMOD_None;
1708 if (key != KSYM_UNDEFINED) // new key => check for modifier key change
1710 KeyMod new_modifier = KMOD_None;
1715 new_modifier = KMOD_Shift_L;
1718 new_modifier = KMOD_Shift_R;
1720 case KSYM_Control_L:
1721 new_modifier = KMOD_Control_L;
1723 case KSYM_Control_R:
1724 new_modifier = KMOD_Control_R;
1727 new_modifier = KMOD_Meta_L;
1730 new_modifier = KMOD_Meta_R;
1733 new_modifier = KMOD_Alt_L;
1736 new_modifier = KMOD_Alt_R;
1742 if (key_status == KEY_PRESSED)
1743 current_modifiers |= new_modifier;
1745 current_modifiers &= ~new_modifier;
1748 return current_modifiers;
1751 KeyMod GetKeyModState(void)
1753 return (KeyMod)SDL_GetModState();
1756 KeyMod GetKeyModStateFromEvents(void)
1758 /* always use key modifier state as tracked from key events (this is needed
1759 if the modifier key event was injected into the event queue, but the key
1760 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1761 query the keys as held pressed on the keyboard) -- this case is currently
1762 only used to filter out clipboard insert events from "True X-Mouse" tool */
1764 return HandleKeyModState(KSYM_UNDEFINED, 0);
1767 void StartTextInput(int x, int y, int width, int height)
1769 textinput_status = TRUE;
1771 #if defined(HAS_SCREEN_KEYBOARD)
1772 SDL_StartTextInput();
1774 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1776 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1777 video.shifted_up_delay = SDL_GetTicks();
1778 video.shifted_up = TRUE;
1783 void StopTextInput(void)
1785 textinput_status = FALSE;
1787 #if defined(HAS_SCREEN_KEYBOARD)
1788 SDL_StopTextInput();
1790 if (video.shifted_up)
1792 video.shifted_up_pos = 0;
1793 video.shifted_up_delay = SDL_GetTicks();
1794 video.shifted_up = FALSE;
1799 void PushUserEvent(int code, int value1, int value2)
1803 SDL_memset(&event, 0, sizeof(event));
1805 event.type = EVENT_USER;
1807 event.value1 = value1;
1808 event.value2 = value2;
1810 SDL_PushEvent((SDL_Event *)&event);
1814 // ============================================================================
1815 // joystick functions
1816 // ============================================================================
1818 void InitJoysticks(void)
1822 #if defined(NO_JOYSTICK)
1823 return; // joysticks generally deactivated by compile-time directive
1826 // always start with reliable default values
1827 joystick.status = JOYSTICK_NOT_AVAILABLE;
1828 for (i = 0; i < MAX_PLAYERS; i++)
1829 joystick.nr[i] = -1; // no joystick configured
1834 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1836 return SDLReadJoystick(nr, x, y, b1, b2);
1839 boolean CheckJoystickOpened(int nr)
1841 return SDLCheckJoystickOpened(nr);
1844 void ClearJoystickState(void)
1846 SDLClearJoystickState();