1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
24 #define ENABLE_UNUSED_CODE 0 /* currently unused functions */
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct OptionInfo options;
33 struct VideoSystemInfo video;
34 struct AudioSystemInfo audio;
36 struct TileCursorInfo tile_cursor;
37 struct OverlayInfo overlay;
38 struct ArtworkInfo artwork;
39 struct JoystickInfo joystick;
40 struct SetupInfo setup;
42 LevelDirTree *leveldir_first_all = NULL;
43 LevelDirTree *leveldir_first = NULL;
44 LevelDirTree *leveldir_current = NULL;
47 struct LevelStats level_stats[MAX_LEVELS];
49 DrawWindow *window = NULL;
50 DrawBuffer *backbuffer = NULL;
51 DrawBuffer *drawto = NULL;
53 int button_status = MB_NOT_PRESSED;
54 boolean motion_status = FALSE;
55 int wheel_steps = DEFAULT_WHEEL_STEPS;
56 #if defined(TARGET_SDL2)
57 boolean keyrepeat_status = TRUE;
60 int redraw_mask = REDRAW_NONE;
65 /* ========================================================================= */
66 /* init/close functions */
67 /* ========================================================================= */
69 void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
70 char *program_title, char *icon_title,
71 char *icon_filename, char *cookie_prefix,
72 char *program_version_string, int program_version)
74 program.command_basepath = getBasePath(argv0);
75 program.command_basename = getBaseName(argv0);
77 program.config_filename = config_filename;
79 program.userdata_subdir = userdata_subdir;
80 program.userdata_path = getUserGameDataDir();
82 program.program_title = program_title;
83 program.window_title = "(undefined)";
84 program.icon_title = icon_title;
86 program.icon_filename = icon_filename;
88 program.cookie_prefix = cookie_prefix;
90 program.version_super = VERSION_SUPER(program_version);
91 program.version_major = VERSION_MAJOR(program_version);
92 program.version_minor = VERSION_MINOR(program_version);
93 program.version_patch = VERSION_PATCH(program_version);
94 program.version_ident = program_version;
96 program.version_string = program_version_string;
98 program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
99 program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
100 program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
101 program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
103 program.headless = FALSE;
106 void InitScoresInfo()
108 char *global_scores_dir = getPath2(getCommonDataDir(), SCORES_DIRECTORY);
110 program.global_scores = directoryExists(global_scores_dir);
111 program.many_scores_per_name = !program.global_scores;
115 if (program.global_scores)
117 Error(ERR_DEBUG, "Using global, multi-user scores directory '%s'.",
119 Error(ERR_DEBUG, "Remove to enable single-user scores directory.");
120 Error(ERR_DEBUG, "(This enables multipe score entries per user.)");
124 Error(ERR_DEBUG, "Using private, single-user scores directory.");
128 free(global_scores_dir);
131 void SetWindowTitle()
133 program.window_title = program.window_title_function();
138 void InitWindowTitleFunction(char *(*window_title_function)(void))
140 program.window_title_function = window_title_function;
143 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
145 program.exit_message_function = exit_message_function;
148 void InitExitFunction(void (*exit_function)(int))
150 program.exit_function = exit_function;
152 /* set signal handlers to custom exit function */
153 // signal(SIGINT, exit_function);
154 signal(SIGTERM, exit_function);
156 /* set exit function to automatically cleanup SDL stuff after exit() */
160 void InitPlatformDependentStuff(void)
162 // this is initialized in GetOptions(), but may already be used before
163 options.verbose = TRUE;
167 #if defined(TARGET_SDL2)
168 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
170 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
173 if (SDL_Init(sdl_init_flags) < 0)
174 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
179 void ClosePlatformDependentStuff(void)
184 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
185 int real_sx, int real_sy,
186 int full_sxsize, int full_sysize,
187 Bitmap *field_save_buffer)
193 gfx.real_sx = real_sx;
194 gfx.real_sy = real_sy;
195 gfx.full_sxsize = full_sxsize;
196 gfx.full_sysize = full_sysize;
198 gfx.field_save_buffer = field_save_buffer;
200 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
201 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
204 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
206 gfx.game_tile_size = game_tile_size;
207 gfx.standard_tile_size = standard_tile_size;
210 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
218 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
226 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
234 void InitGfxWindowInfo(int win_xsize, int win_ysize)
236 if (win_xsize != gfx.win_xsize || win_ysize != gfx.win_ysize)
238 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize);
240 #if defined(TARGET_SDL2)
241 ReCreateBitmap(&gfx.final_screen_bitmap, win_xsize, win_ysize);
244 ReCreateBitmap(&gfx.fade_bitmap_backup, win_xsize, win_ysize);
245 ReCreateBitmap(&gfx.fade_bitmap_source, win_xsize, win_ysize);
246 ReCreateBitmap(&gfx.fade_bitmap_target, win_xsize, win_ysize);
247 ReCreateBitmap(&gfx.fade_bitmap_black, win_xsize, win_ysize);
249 ClearRectangle(gfx.fade_bitmap_black, 0, 0, win_xsize, win_ysize);
252 gfx.win_xsize = win_xsize;
253 gfx.win_ysize = win_ysize;
255 gfx.background_bitmap_mask = REDRAW_NONE;
258 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
260 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
261 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
262 gfx.scrollbuffer_width = scrollbuffer_width;
263 gfx.scrollbuffer_height = scrollbuffer_height;
266 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
268 gfx.clipping_enabled = enabled;
271 gfx.clip_width = width;
272 gfx.clip_height = height;
275 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
277 gfx.draw_busy_anim_function = draw_busy_anim_function;
280 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int))
282 gfx.draw_global_anim_function = draw_global_anim_function;
285 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
287 gfx.draw_global_border_function = draw_global_border_function;
290 void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
292 gfx.draw_tile_cursor_function = draw_tile_cursor_function;
295 void InitGfxCustomArtworkInfo()
297 gfx.override_level_graphics = FALSE;
298 gfx.override_level_sounds = FALSE;
299 gfx.override_level_music = FALSE;
301 gfx.draw_init_text = TRUE;
304 void InitGfxOtherSettings()
306 gfx.cursor_mode = CURSOR_DEFAULT;
309 void InitTileCursorInfo()
311 tile_cursor.enabled = FALSE;
312 tile_cursor.active = FALSE;
313 tile_cursor.moving = FALSE;
315 tile_cursor.xpos = 0;
316 tile_cursor.ypos = 0;
319 tile_cursor.target_x = 0;
320 tile_cursor.target_y = 0;
326 void InitOverlayInfo()
328 overlay.enabled = FALSE;
329 overlay.active = FALSE;
331 #if defined(PLATFORM_ANDROID)
332 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
333 overlay.enabled = TRUE;
337 void SetTileCursorEnabled(boolean enabled)
339 tile_cursor.enabled = enabled;
342 void SetTileCursorActive(boolean active)
344 tile_cursor.active = active;
347 void SetTileCursorTargetXY(int x, int y)
349 // delayed placement of tile selection cursor at target position
350 // (tile cursor will be moved to target position step by step)
352 tile_cursor.xpos = x;
353 tile_cursor.ypos = y;
354 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
355 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
357 tile_cursor.moving = TRUE;
360 void SetTileCursorXY(int x, int y)
362 // immediate placement of tile selection cursor at target position
364 SetTileCursorTargetXY(x, y);
366 tile_cursor.x = tile_cursor.target_x;
367 tile_cursor.y = tile_cursor.target_y;
369 tile_cursor.moving = FALSE;
372 void SetTileCursorSXSY(int sx, int sy)
378 void SetOverlayEnabled(boolean enabled)
380 overlay.enabled = enabled;
383 void SetOverlayActive(boolean active)
385 overlay.active = active;
388 boolean GetOverlayActive()
390 return overlay.active;
393 void SetDrawDeactivationMask(int draw_deactivation_mask)
395 gfx.draw_deactivation_mask = draw_deactivation_mask;
398 int GetDrawDeactivationMask()
400 return gfx.draw_deactivation_mask;
403 void SetDrawBackgroundMask(int draw_background_mask)
405 gfx.draw_background_mask = draw_background_mask;
408 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
410 if (background_bitmap_tile != NULL)
411 gfx.background_bitmap_mask |= mask;
413 gfx.background_bitmap_mask &= ~mask;
415 if (background_bitmap_tile == NULL) /* empty background requested */
418 if (mask == REDRAW_ALL)
419 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
420 0, 0, video.width, video.height);
421 else if (mask == REDRAW_FIELD)
422 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
423 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
424 else if (mask == REDRAW_DOOR_1)
425 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
426 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
429 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
431 /* remove every mask before setting mask for window */
432 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
433 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
434 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
437 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
439 /* remove window area mask before setting mask for main area */
440 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
441 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
442 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
445 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
447 /* remove window area mask before setting mask for door area */
448 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
449 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
450 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
454 /* ========================================================================= */
455 /* video functions */
456 /* ========================================================================= */
458 inline static int GetRealDepth(int depth)
460 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
463 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
464 int width, int height, Pixel color)
466 SDLFillRectangle(bitmap, x, y, width, height, color);
468 if (bitmap == backbuffer)
469 SetRedrawMaskFromArea(x, y, width, height);
472 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
473 int src_x, int src_y, int width, int height,
474 int dst_x, int dst_y, int mask_mode)
476 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
477 dst_x, dst_y, mask_mode);
479 if (dst_bitmap == backbuffer)
480 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
483 void LimitScreenUpdates(boolean enable)
485 SDLLimitScreenUpdates(enable);
488 void InitVideoDefaults(void)
490 video.default_depth = 32;
493 void InitVideoDisplay(void)
495 if (program.headless)
498 SDLInitVideoDisplay();
499 #if defined(TARGET_SDL2)
504 void CloseVideoDisplay(void)
506 KeyboardAutoRepeatOn();
508 SDL_QuitSubSystem(SDL_INIT_VIDEO);
511 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
514 video.height = height;
515 video.depth = GetRealDepth(depth);
517 video.screen_width = width;
518 video.screen_height = height;
519 video.screen_xoffset = 0;
520 video.screen_yoffset = 0;
522 video.fullscreen_available = FULLSCREEN_STATUS;
523 video.fullscreen_enabled = FALSE;
525 video.window_scaling_available = WINDOW_SCALING_STATUS;
527 video.frame_delay = 0;
528 video.frame_delay_value = GAME_FRAME_DELAY;
530 video.shifted_up = FALSE;
531 video.shifted_up_pos = 0;
532 video.shifted_up_pos_last = 0;
533 video.shifted_up_delay = 0;
534 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
536 SDLInitVideoBuffer(fullscreen);
538 video.initialized = !program.headless;
543 inline static void FreeBitmapPointers(Bitmap *bitmap)
548 SDLFreeBitmapPointers(bitmap);
550 checked_free(bitmap->source_filename);
551 bitmap->source_filename = NULL;
554 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
557 if (src_bitmap == NULL || dst_bitmap == NULL)
560 FreeBitmapPointers(dst_bitmap);
562 *dst_bitmap = *src_bitmap;
565 void FreeBitmap(Bitmap *bitmap)
570 FreeBitmapPointers(bitmap);
575 Bitmap *CreateBitmapStruct(void)
577 return checked_calloc(sizeof(Bitmap));
580 Bitmap *CreateBitmap(int width, int height, int depth)
582 Bitmap *new_bitmap = CreateBitmapStruct();
583 int real_width = MAX(1, width); /* prevent zero bitmap width */
584 int real_height = MAX(1, height); /* prevent zero bitmap height */
585 int real_depth = GetRealDepth(depth);
587 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
589 new_bitmap->width = real_width;
590 new_bitmap->height = real_height;
595 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
599 /* if new bitmap size fits into old one, no need to re-create it */
600 if (width <= (*bitmap)->width &&
601 height <= (*bitmap)->height)
604 /* else adjust size so that old and new bitmap size fit into it */
605 width = MAX(width, (*bitmap)->width);
606 height = MAX(height, (*bitmap)->height);
609 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
613 *bitmap = new_bitmap;
617 TransferBitmapPointers(new_bitmap, *bitmap);
622 void CloseWindow(DrawWindow *window)
626 void SetRedrawMaskFromArea(int x, int y, int width, int height)
630 int x2 = x + width - 1;
631 int y2 = y + height - 1;
633 if (width == 0 || height == 0)
636 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
637 redraw_mask |= REDRAW_FIELD;
638 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
639 redraw_mask |= REDRAW_DOOR_1;
640 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
641 redraw_mask |= REDRAW_DOOR_2;
642 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
643 redraw_mask |= REDRAW_DOOR_3;
645 redraw_mask = REDRAW_ALL;
648 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
651 if (draw_mask == REDRAW_NONE)
654 if (draw_mask & REDRAW_ALL)
657 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
660 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
663 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
666 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
672 boolean DrawingDeactivatedField()
674 if (program.headless)
677 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
683 boolean DrawingDeactivated(int x, int y, int width, int height)
685 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
688 boolean DrawingOnBackground(int x, int y)
690 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
691 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
694 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
695 int *width, int *height, boolean is_dest)
697 int clip_x, clip_y, clip_width, clip_height;
699 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
701 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
702 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
703 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
704 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
710 clip_width = bitmap->width;
711 clip_height = bitmap->height;
714 /* skip if rectangle completely outside bitmap */
716 if (*x + *width <= clip_x ||
717 *y + *height <= clip_y ||
718 *x >= clip_x + clip_width ||
719 *y >= clip_y + clip_height)
722 /* clip if rectangle overlaps bitmap */
726 *width -= clip_x - *x;
729 else if (*x + *width > clip_x + clip_width)
731 *width = clip_x + clip_width - *x;
736 *height -= clip_y - *y;
739 else if (*y + *height > clip_y + clip_height)
741 *height = clip_y + clip_height - *y;
747 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
748 int src_x, int src_y, int width, int height,
749 int dst_x, int dst_y)
751 int dst_x_unclipped = dst_x;
752 int dst_y_unclipped = dst_y;
754 if (program.headless)
757 if (src_bitmap == NULL || dst_bitmap == NULL)
760 if (DrawingDeactivated(dst_x, dst_y, width, height))
763 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
764 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
767 /* source x/y might need adjustment if destination x/y was clipped top/left */
768 src_x += dst_x - dst_x_unclipped;
769 src_y += dst_y - dst_y_unclipped;
771 #if defined(TARGET_SDL2)
772 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
773 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
774 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
775 but is already fixed in SVN and should therefore finally be fixed with
776 the next official SDL release, which is probably version 1.2.14.) */
777 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
779 if (src_bitmap == dst_bitmap)
781 /* needed when blitting directly to same bitmap -- should not be needed with
782 recent SDL libraries, but apparently does not work in 1.2.11 directly */
784 static Bitmap *tmp_bitmap = NULL;
785 static int tmp_bitmap_xsize = 0;
786 static int tmp_bitmap_ysize = 0;
788 /* start with largest static bitmaps for initial bitmap size ... */
789 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
791 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
792 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
795 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
796 if (src_bitmap->width > tmp_bitmap_xsize ||
797 src_bitmap->height > tmp_bitmap_ysize)
799 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
800 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
802 FreeBitmap(tmp_bitmap);
807 if (tmp_bitmap == NULL)
808 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
811 sysCopyArea(src_bitmap, tmp_bitmap,
812 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
813 sysCopyArea(tmp_bitmap, dst_bitmap,
814 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
820 sysCopyArea(src_bitmap, dst_bitmap,
821 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
824 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
825 int src_x, int src_y, int src_width, int src_height,
826 int dst_x, int dst_y, int dst_width, int dst_height)
828 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
829 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
830 int dst_xsize = dst_width;
831 int dst_ysize = dst_height;
832 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
833 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
836 for (y = 0; y < src_ysteps; y++)
838 for (x = 0; x < src_xsteps; x++)
840 int draw_x = dst_x + x * src_xsize;
841 int draw_y = dst_y + y * src_ysize;
842 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
843 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
845 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
851 void FadeRectangle(int x, int y, int width, int height,
852 int fade_mode, int fade_delay, int post_delay,
853 void (*draw_border_function)(void))
855 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
856 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
859 SDLFadeRectangle(x, y, width, height,
860 fade_mode, fade_delay, post_delay, draw_border_function);
863 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
866 if (DrawingDeactivated(x, y, width, height))
869 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
872 sysFillRectangle(bitmap, x, y, width, height, color);
875 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
877 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
880 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
881 int width, int height)
883 if (DrawingOnBackground(x, y))
884 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
886 ClearRectangle(bitmap, x, y, width, height);
889 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
890 int src_x, int src_y, int width, int height,
891 int dst_x, int dst_y)
893 if (DrawingDeactivated(dst_x, dst_y, width, height))
896 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
897 dst_x, dst_y, BLIT_MASKED);
900 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
901 int src_x, int src_y, int width, int height,
902 int dst_x, int dst_y)
904 if (DrawingOnBackground(dst_x, dst_y))
906 /* draw background */
907 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
910 /* draw foreground */
911 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
915 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
919 void BlitTexture(Bitmap *bitmap,
920 int src_x, int src_y, int width, int height,
921 int dst_x, int dst_y)
926 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
930 void BlitTextureMasked(Bitmap *bitmap,
931 int src_x, int src_y, int width, int height,
932 int dst_x, int dst_y)
937 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
941 void BlitToScreen(Bitmap *bitmap,
942 int src_x, int src_y, int width, int height,
943 int dst_x, int dst_y)
948 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
949 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
950 width, height, dst_x, dst_y);
952 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
955 void BlitToScreenMasked(Bitmap *bitmap,
956 int src_x, int src_y, int width, int height,
957 int dst_x, int dst_y)
962 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
963 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
964 width, height, dst_x, dst_y);
966 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
969 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
972 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
975 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
978 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
981 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
982 int to_x, int to_y, Pixel pixel, int line_width)
986 if (program.headless)
989 for (x = 0; x < line_width; x++)
991 for (y = 0; y < line_width; y++)
993 int dx = x - line_width / 2;
994 int dy = y - line_width / 2;
996 if ((x == 0 && y == 0) ||
997 (x == 0 && y == line_width - 1) ||
998 (x == line_width - 1 && y == 0) ||
999 (x == line_width - 1 && y == line_width - 1))
1003 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1008 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1013 for (i = 0; i < num_points - 1; i++)
1014 DrawLine(bitmap, points[i].x, points[i].y,
1015 points[i + 1].x, points[i + 1].y, pixel, line_width);
1018 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1022 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1024 if (program.headless)
1027 if (x < 0 || x >= bitmap->width ||
1028 y < 0 || y >= bitmap->height)
1031 return SDLGetPixel(bitmap, x, y);
1034 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1035 unsigned int color_g, unsigned int color_b)
1037 if (program.headless)
1040 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1043 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1045 unsigned int color_r = (color >> 16) & 0xff;
1046 unsigned int color_g = (color >> 8) & 0xff;
1047 unsigned int color_b = (color >> 0) & 0xff;
1049 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1052 void KeyboardAutoRepeatOn(void)
1054 #if defined(TARGET_SDL2)
1055 keyrepeat_status = TRUE;
1057 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1058 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1059 SDL_EnableUNICODE(1);
1063 void KeyboardAutoRepeatOff(void)
1065 #if defined(TARGET_SDL2)
1066 keyrepeat_status = FALSE;
1068 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1069 SDL_EnableUNICODE(0);
1073 boolean SetVideoMode(boolean fullscreen)
1075 return SDLSetVideoMode(fullscreen);
1078 void SetVideoFrameDelay(unsigned int frame_delay_value)
1080 video.frame_delay_value = frame_delay_value;
1083 unsigned int GetVideoFrameDelay()
1085 return video.frame_delay_value;
1088 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1090 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1091 (!fullscreen && video.fullscreen_enabled))
1092 fullscreen = SetVideoMode(fullscreen);
1097 Bitmap *LoadImage(char *filename)
1101 new_bitmap = SDLLoadImage(filename);
1104 new_bitmap->source_filename = getStringCopy(filename);
1109 Bitmap *LoadCustomImage(char *basename)
1111 char *filename = getCustomImageFilename(basename);
1114 if (filename == NULL)
1115 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1117 if ((new_bitmap = LoadImage(filename)) == NULL)
1118 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1123 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1125 char *filename = getCustomImageFilename(basename);
1128 if (filename == NULL) /* (should never happen) */
1130 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1134 if (strEqual(filename, bitmap->source_filename))
1136 /* The old and new image are the same (have the same filename and path).
1137 This usually means that this image does not exist in this graphic set
1138 and a fallback to the existing image is done. */
1143 if ((new_bitmap = LoadImage(filename)) == NULL)
1145 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1149 if (bitmap->width != new_bitmap->width ||
1150 bitmap->height != new_bitmap->height)
1152 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1154 FreeBitmap(new_bitmap);
1158 TransferBitmapPointers(new_bitmap, bitmap);
1162 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1164 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1167 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1169 if (bitmaps[IMG_BITMAP_CUSTOM])
1171 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1173 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1176 if (gfx.game_tile_size == gfx.standard_tile_size)
1178 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1183 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1184 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1185 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1187 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1189 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1190 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1193 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1194 int tile_size, boolean create_small_bitmaps)
1196 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1197 Bitmap *tmp_bitmap_final = NULL;
1198 Bitmap *tmp_bitmap_0 = NULL;
1199 Bitmap *tmp_bitmap_1 = NULL;
1200 Bitmap *tmp_bitmap_2 = NULL;
1201 Bitmap *tmp_bitmap_4 = NULL;
1202 Bitmap *tmp_bitmap_8 = NULL;
1203 Bitmap *tmp_bitmap_16 = NULL;
1204 Bitmap *tmp_bitmap_32 = NULL;
1205 int width_final, height_final;
1206 int width_0, height_0;
1207 int width_1, height_1;
1208 int width_2, height_2;
1209 int width_4, height_4;
1210 int width_8, height_8;
1211 int width_16, height_16;
1212 int width_32, height_32;
1213 int old_width, old_height;
1216 print_timestamp_init("CreateScaledBitmaps");
1218 old_width = old_bitmap->width;
1219 old_height = old_bitmap->height;
1221 /* calculate new image dimensions for final image size */
1222 width_final = old_width * zoom_factor;
1223 height_final = old_height * zoom_factor;
1225 /* get image with final size (this might require scaling up) */
1226 /* ("final" size may result in non-standard tile size image) */
1227 if (zoom_factor != 1)
1228 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1230 tmp_bitmap_final = old_bitmap;
1232 UPDATE_BUSY_STATE();
1234 width_0 = width_1 = width_final;
1235 height_0 = height_1 = height_final;
1237 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1239 if (create_small_bitmaps)
1241 /* check if we have a non-gameplay tile size image */
1242 if (tile_size != gfx.game_tile_size)
1244 /* get image with gameplay tile size */
1245 width_0 = width_final * gfx.game_tile_size / tile_size;
1246 height_0 = height_final * gfx.game_tile_size / tile_size;
1248 if (width_0 == old_width)
1249 tmp_bitmap_0 = old_bitmap;
1250 else if (width_0 == width_final)
1251 tmp_bitmap_0 = tmp_bitmap_final;
1253 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1255 UPDATE_BUSY_STATE();
1258 /* check if we have a non-standard tile size image */
1259 if (tile_size != gfx.standard_tile_size)
1261 /* get image with standard tile size */
1262 width_1 = width_final * gfx.standard_tile_size / tile_size;
1263 height_1 = height_final * gfx.standard_tile_size / tile_size;
1265 if (width_1 == old_width)
1266 tmp_bitmap_1 = old_bitmap;
1267 else if (width_1 == width_final)
1268 tmp_bitmap_1 = tmp_bitmap_final;
1269 else if (width_1 == width_0)
1270 tmp_bitmap_1 = tmp_bitmap_0;
1272 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1274 UPDATE_BUSY_STATE();
1277 /* calculate new image dimensions for small images */
1278 width_2 = width_1 / 2;
1279 height_2 = height_1 / 2;
1280 width_4 = width_1 / 4;
1281 height_4 = height_1 / 4;
1282 width_8 = width_1 / 8;
1283 height_8 = height_1 / 8;
1284 width_16 = width_1 / 16;
1285 height_16 = height_1 / 16;
1286 width_32 = width_1 / 32;
1287 height_32 = height_1 / 32;
1289 /* get image with 1/2 of normal size (for use in the level editor) */
1290 if (width_2 == old_width)
1291 tmp_bitmap_2 = old_bitmap;
1293 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1295 UPDATE_BUSY_STATE();
1297 /* get image with 1/4 of normal size (for use in the level editor) */
1298 if (width_4 == old_width)
1299 tmp_bitmap_4 = old_bitmap;
1301 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1303 UPDATE_BUSY_STATE();
1305 /* get image with 1/8 of normal size (for use on the preview screen) */
1306 if (width_8 == old_width)
1307 tmp_bitmap_8 = old_bitmap;
1309 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1311 UPDATE_BUSY_STATE();
1313 /* get image with 1/16 of normal size (for use on the preview screen) */
1314 if (width_16 == old_width)
1315 tmp_bitmap_16 = old_bitmap;
1317 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1319 UPDATE_BUSY_STATE();
1321 /* get image with 1/32 of normal size (for use on the preview screen) */
1322 if (width_32 == old_width)
1323 tmp_bitmap_32 = old_bitmap;
1325 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1327 UPDATE_BUSY_STATE();
1329 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1330 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1331 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1332 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1333 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1334 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1336 if (width_0 != width_1)
1337 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1339 if (bitmaps[IMG_BITMAP_CUSTOM])
1340 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1342 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1344 boolean free_old_bitmap = TRUE;
1346 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1347 if (bitmaps[i] == old_bitmap)
1348 free_old_bitmap = FALSE;
1350 if (free_old_bitmap)
1351 FreeBitmap(old_bitmap);
1355 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1358 UPDATE_BUSY_STATE();
1360 print_timestamp_done("CreateScaledBitmaps");
1363 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1366 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1369 void CreateBitmapTextures(Bitmap **bitmaps)
1371 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1374 void FreeBitmapTextures(Bitmap **bitmaps)
1376 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1379 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1381 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1385 /* ------------------------------------------------------------------------- */
1386 /* mouse pointer functions */
1387 /* ------------------------------------------------------------------------- */
1389 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1391 /* XPM image definitions */
1392 static const char *cursor_image_none[] =
1394 /* width height num_colors chars_per_pixel */
1424 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1425 static const char *cursor_image_dot[] =
1427 /* width height num_colors chars_per_pixel */
1456 static const char **cursor_image_playfield = cursor_image_dot;
1458 /* some people complained about a "white dot" on the screen and thought it
1459 was a graphical error... OK, let's just remove the whole pointer :-) */
1460 static const char **cursor_image_playfield = cursor_image_none;
1463 static const int cursor_bit_order = BIT_ORDER_MSB;
1465 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1467 struct MouseCursorInfo *cursor;
1468 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1469 int header_lines = 4;
1472 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1474 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1477 for (y = 0; y < cursor->width; y++)
1479 for (x = 0; x < cursor->height; x++)
1482 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1487 cursor->data[i] = cursor->mask[i] = 0;
1490 switch (image[header_lines + y][x])
1493 cursor->data[i] |= bit_mask;
1494 cursor->mask[i] |= bit_mask;
1498 cursor->mask[i] |= bit_mask;
1507 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1512 void SetMouseCursor(int mode)
1514 static struct MouseCursorInfo *cursor_none = NULL;
1515 static struct MouseCursorInfo *cursor_playfield = NULL;
1516 struct MouseCursorInfo *cursor_new;
1518 if (cursor_none == NULL)
1519 cursor_none = get_cursor_from_image(cursor_image_none);
1521 if (cursor_playfield == NULL)
1522 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1524 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1525 mode == CURSOR_NONE ? cursor_none :
1526 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1528 SDLSetMouseCursor(cursor_new);
1530 gfx.cursor_mode = mode;
1534 /* ========================================================================= */
1535 /* audio functions */
1536 /* ========================================================================= */
1538 void OpenAudio(void)
1540 /* always start with reliable default values */
1541 audio.sound_available = FALSE;
1542 audio.music_available = FALSE;
1543 audio.loops_available = FALSE;
1545 audio.sound_enabled = FALSE;
1546 audio.sound_deactivated = FALSE;
1548 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1549 audio.mixer_pid = 0;
1550 audio.device_name = NULL;
1551 audio.device_fd = -1;
1553 audio.num_channels = 0;
1554 audio.music_channel = 0;
1555 audio.first_sound_channel = 0;
1560 void CloseAudio(void)
1564 audio.sound_enabled = FALSE;
1567 void SetAudioMode(boolean enabled)
1569 if (!audio.sound_available)
1572 audio.sound_enabled = enabled;
1576 /* ========================================================================= */
1577 /* event functions */
1578 /* ========================================================================= */
1580 boolean PendingEvent(void)
1582 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1585 void WaitEvent(Event *event)
1587 SDLWaitEvent(event);
1590 void PeekEvent(Event *event)
1592 #if defined(TARGET_SDL2)
1593 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1595 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1599 void CheckQuitEvent(void)
1601 if (SDL_QuitRequested())
1602 program.exit_function(0);
1605 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1607 #if defined(TARGET_SDL2)
1608 /* key up/down events in SDL2 do not return text characters anymore */
1609 return event->keysym.sym;
1612 #if ENABLE_UNUSED_CODE
1613 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1614 (int)event->keysym.unicode,
1615 (int)event->keysym.sym,
1616 (int)SDL_GetModState());
1619 if (with_modifiers &&
1620 event->keysym.unicode > 0x0000 &&
1621 event->keysym.unicode < 0x2000)
1622 return event->keysym.unicode;
1624 return event->keysym.sym;
1629 KeyMod HandleKeyModState(Key key, int key_status)
1631 static KeyMod current_modifiers = KMOD_None;
1633 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1635 KeyMod new_modifier = KMOD_None;
1640 new_modifier = KMOD_Shift_L;
1643 new_modifier = KMOD_Shift_R;
1645 case KSYM_Control_L:
1646 new_modifier = KMOD_Control_L;
1648 case KSYM_Control_R:
1649 new_modifier = KMOD_Control_R;
1652 new_modifier = KMOD_Meta_L;
1655 new_modifier = KMOD_Meta_R;
1658 new_modifier = KMOD_Alt_L;
1661 new_modifier = KMOD_Alt_R;
1667 if (key_status == KEY_PRESSED)
1668 current_modifiers |= new_modifier;
1670 current_modifiers &= ~new_modifier;
1673 return current_modifiers;
1676 KeyMod GetKeyModState()
1678 return (KeyMod)SDL_GetModState();
1681 KeyMod GetKeyModStateFromEvents()
1683 /* always use key modifier state as tracked from key events (this is needed
1684 if the modifier key event was injected into the event queue, but the key
1685 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1686 query the keys as held pressed on the keyboard) -- this case is currently
1687 only used to filter out clipboard insert events from "True X-Mouse" tool */
1689 return HandleKeyModState(KSYM_UNDEFINED, 0);
1692 void StartTextInput(int x, int y, int width, int height)
1694 #if defined(TARGET_SDL2)
1695 #if defined(HAS_SCREEN_KEYBOARD)
1696 SDL_StartTextInput();
1698 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1700 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1701 video.shifted_up_delay = SDL_GetTicks();
1702 video.shifted_up = TRUE;
1708 void StopTextInput()
1710 #if defined(TARGET_SDL2)
1711 #if defined(HAS_SCREEN_KEYBOARD)
1712 SDL_StopTextInput();
1714 if (video.shifted_up)
1716 video.shifted_up_pos = 0;
1717 video.shifted_up_delay = SDL_GetTicks();
1718 video.shifted_up = FALSE;
1724 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1726 if (event->type != EVENT_CLIENTMESSAGE)
1729 return TRUE; /* the only possible message here is SDL_QUIT */
1733 /* ========================================================================= */
1734 /* joystick functions */
1735 /* ========================================================================= */
1737 void InitJoysticks()
1741 #if defined(NO_JOYSTICK)
1742 return; /* joysticks generally deactivated by compile-time directive */
1745 /* always start with reliable default values */
1746 joystick.status = JOYSTICK_NOT_AVAILABLE;
1747 for (i = 0; i < MAX_PLAYERS; i++)
1748 joystick.nr[i] = -1; /* no joystick configured */
1753 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1755 return SDLReadJoystick(nr, x, y, b1, b2);
1758 boolean CheckJoystickOpened(int nr)
1760 return SDLCheckJoystickOpened(nr);
1763 void ClearJoystickState()
1765 SDLClearJoystickState();