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_major = VERSION_MAJOR(program_version);
91 program.version_minor = VERSION_MINOR(program_version);
92 program.version_patch = VERSION_PATCH(program_version);
93 program.version_build = VERSION_BUILD(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;
323 void InitOverlayInfo()
325 overlay.enabled = FALSE;
326 overlay.active = FALSE;
328 #if defined(PLATFORM_ANDROID)
329 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
330 overlay.enabled = TRUE;
334 void SetTileCursorEnabled(boolean enabled)
336 tile_cursor.enabled = enabled;
339 void SetTileCursorActive(boolean active)
341 tile_cursor.active = active;
344 void SetTileCursorTargetXY(int x, int y)
346 // delayed placement of tile selection cursor at target position
347 // (tile cursor will be moved to target position step by step)
349 tile_cursor.xpos = x;
350 tile_cursor.ypos = y;
351 tile_cursor.target_x = gfx.sx + x * gfx.game_tile_size;
352 tile_cursor.target_y = gfx.sy + y * gfx.game_tile_size;
354 tile_cursor.moving = TRUE;
357 void SetTileCursorXY(int x, int y)
359 // immediate placement of tile selection cursor at target position
361 SetTileCursorTargetXY(x, y);
363 tile_cursor.x = tile_cursor.target_x;
364 tile_cursor.y = tile_cursor.target_y;
366 tile_cursor.moving = FALSE;
369 void SetOverlayEnabled(boolean enabled)
371 overlay.enabled = enabled;
374 void SetOverlayActive(boolean active)
376 overlay.active = active;
379 boolean GetOverlayActive()
381 return overlay.active;
384 void SetDrawDeactivationMask(int draw_deactivation_mask)
386 gfx.draw_deactivation_mask = draw_deactivation_mask;
389 int GetDrawDeactivationMask()
391 return gfx.draw_deactivation_mask;
394 void SetDrawBackgroundMask(int draw_background_mask)
396 gfx.draw_background_mask = draw_background_mask;
399 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
401 if (background_bitmap_tile != NULL)
402 gfx.background_bitmap_mask |= mask;
404 gfx.background_bitmap_mask &= ~mask;
406 if (background_bitmap_tile == NULL) /* empty background requested */
409 if (mask == REDRAW_ALL)
410 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
411 0, 0, video.width, video.height);
412 else if (mask == REDRAW_FIELD)
413 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
414 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
415 else if (mask == REDRAW_DOOR_1)
416 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
417 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
420 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
422 /* remove every mask before setting mask for window */
423 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
424 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
425 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
428 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
430 /* remove window area mask before setting mask for main area */
431 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
432 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
433 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
436 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
438 /* remove window area mask before setting mask for door area */
439 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
440 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
441 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
445 /* ========================================================================= */
446 /* video functions */
447 /* ========================================================================= */
449 inline static int GetRealDepth(int depth)
451 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
454 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
455 int width, int height, Pixel color)
457 SDLFillRectangle(bitmap, x, y, width, height, color);
459 if (bitmap == backbuffer)
460 SetRedrawMaskFromArea(x, y, width, height);
463 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
464 int src_x, int src_y, int width, int height,
465 int dst_x, int dst_y, int mask_mode)
467 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
468 dst_x, dst_y, mask_mode);
470 if (dst_bitmap == backbuffer)
471 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
474 void LimitScreenUpdates(boolean enable)
476 SDLLimitScreenUpdates(enable);
479 void InitVideoDefaults(void)
481 video.default_depth = 32;
484 void InitVideoDisplay(void)
486 if (program.headless)
489 SDLInitVideoDisplay();
490 #if defined(TARGET_SDL2)
495 void CloseVideoDisplay(void)
497 KeyboardAutoRepeatOn();
499 SDL_QuitSubSystem(SDL_INIT_VIDEO);
502 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
505 video.height = height;
506 video.depth = GetRealDepth(depth);
508 video.screen_width = width;
509 video.screen_height = height;
510 video.screen_xoffset = 0;
511 video.screen_yoffset = 0;
513 video.fullscreen_available = FULLSCREEN_STATUS;
514 video.fullscreen_enabled = FALSE;
516 video.window_scaling_available = WINDOW_SCALING_STATUS;
518 video.frame_delay = 0;
519 video.frame_delay_value = GAME_FRAME_DELAY;
521 video.shifted_up = FALSE;
522 video.shifted_up_pos = 0;
523 video.shifted_up_pos_last = 0;
524 video.shifted_up_delay = 0;
525 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
527 SDLInitVideoBuffer(fullscreen);
529 video.initialized = !program.headless;
534 inline static void FreeBitmapPointers(Bitmap *bitmap)
539 SDLFreeBitmapPointers(bitmap);
541 checked_free(bitmap->source_filename);
542 bitmap->source_filename = NULL;
545 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
548 if (src_bitmap == NULL || dst_bitmap == NULL)
551 FreeBitmapPointers(dst_bitmap);
553 *dst_bitmap = *src_bitmap;
556 void FreeBitmap(Bitmap *bitmap)
561 FreeBitmapPointers(bitmap);
566 Bitmap *CreateBitmapStruct(void)
568 return checked_calloc(sizeof(Bitmap));
571 Bitmap *CreateBitmap(int width, int height, int depth)
573 Bitmap *new_bitmap = CreateBitmapStruct();
574 int real_width = MAX(1, width); /* prevent zero bitmap width */
575 int real_height = MAX(1, height); /* prevent zero bitmap height */
576 int real_depth = GetRealDepth(depth);
578 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
580 new_bitmap->width = real_width;
581 new_bitmap->height = real_height;
586 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
590 /* if new bitmap size fits into old one, no need to re-create it */
591 if (width <= (*bitmap)->width &&
592 height <= (*bitmap)->height)
595 /* else adjust size so that old and new bitmap size fit into it */
596 width = MAX(width, (*bitmap)->width);
597 height = MAX(height, (*bitmap)->height);
600 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
604 *bitmap = new_bitmap;
608 TransferBitmapPointers(new_bitmap, *bitmap);
613 void CloseWindow(DrawWindow *window)
617 void SetRedrawMaskFromArea(int x, int y, int width, int height)
621 int x2 = x + width - 1;
622 int y2 = y + height - 1;
624 if (width == 0 || height == 0)
627 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
628 redraw_mask |= REDRAW_FIELD;
629 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
630 redraw_mask |= REDRAW_DOOR_1;
631 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
632 redraw_mask |= REDRAW_DOOR_2;
633 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
634 redraw_mask |= REDRAW_DOOR_3;
636 redraw_mask = REDRAW_ALL;
639 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
642 if (draw_mask == REDRAW_NONE)
645 if (draw_mask & REDRAW_ALL)
648 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
651 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
654 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
657 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
663 boolean DrawingDeactivatedField()
665 if (program.headless)
668 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
674 boolean DrawingDeactivated(int x, int y, int width, int height)
676 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
679 boolean DrawingOnBackground(int x, int y)
681 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
682 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
685 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
686 int *width, int *height, boolean is_dest)
688 int clip_x, clip_y, clip_width, clip_height;
690 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
692 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
693 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
694 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
695 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
701 clip_width = bitmap->width;
702 clip_height = bitmap->height;
705 /* skip if rectangle completely outside bitmap */
707 if (*x + *width <= clip_x ||
708 *y + *height <= clip_y ||
709 *x >= clip_x + clip_width ||
710 *y >= clip_y + clip_height)
713 /* clip if rectangle overlaps bitmap */
717 *width -= clip_x - *x;
720 else if (*x + *width > clip_x + clip_width)
722 *width = clip_x + clip_width - *x;
727 *height -= clip_y - *y;
730 else if (*y + *height > clip_y + clip_height)
732 *height = clip_y + clip_height - *y;
738 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
739 int src_x, int src_y, int width, int height,
740 int dst_x, int dst_y)
742 int dst_x_unclipped = dst_x;
743 int dst_y_unclipped = dst_y;
745 if (program.headless)
748 if (src_bitmap == NULL || dst_bitmap == NULL)
751 if (DrawingDeactivated(dst_x, dst_y, width, height))
754 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
755 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
758 /* source x/y might need adjustment if destination x/y was clipped top/left */
759 src_x += dst_x - dst_x_unclipped;
760 src_y += dst_y - dst_y_unclipped;
762 #if defined(TARGET_SDL2)
763 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
764 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
765 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
766 but is already fixed in SVN and should therefore finally be fixed with
767 the next official SDL release, which is probably version 1.2.14.) */
768 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
770 if (src_bitmap == dst_bitmap)
772 /* needed when blitting directly to same bitmap -- should not be needed with
773 recent SDL libraries, but apparently does not work in 1.2.11 directly */
775 static Bitmap *tmp_bitmap = NULL;
776 static int tmp_bitmap_xsize = 0;
777 static int tmp_bitmap_ysize = 0;
779 /* start with largest static bitmaps for initial bitmap size ... */
780 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
782 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
783 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
786 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
787 if (src_bitmap->width > tmp_bitmap_xsize ||
788 src_bitmap->height > tmp_bitmap_ysize)
790 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
791 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
793 FreeBitmap(tmp_bitmap);
798 if (tmp_bitmap == NULL)
799 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
802 sysCopyArea(src_bitmap, tmp_bitmap,
803 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
804 sysCopyArea(tmp_bitmap, dst_bitmap,
805 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
811 sysCopyArea(src_bitmap, dst_bitmap,
812 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
815 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
816 int src_x, int src_y, int src_width, int src_height,
817 int dst_x, int dst_y, int dst_width, int dst_height)
819 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
820 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
821 int dst_xsize = dst_width;
822 int dst_ysize = dst_height;
823 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
824 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
827 for (y = 0; y < src_ysteps; y++)
829 for (x = 0; x < src_xsteps; x++)
831 int draw_x = dst_x + x * src_xsize;
832 int draw_y = dst_y + y * src_ysize;
833 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
834 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
836 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
842 void FadeRectangle(int x, int y, int width, int height,
843 int fade_mode, int fade_delay, int post_delay,
844 void (*draw_border_function)(void))
846 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
847 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
850 SDLFadeRectangle(x, y, width, height,
851 fade_mode, fade_delay, post_delay, draw_border_function);
854 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
857 if (DrawingDeactivated(x, y, width, height))
860 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
863 sysFillRectangle(bitmap, x, y, width, height, color);
866 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
868 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
871 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
872 int width, int height)
874 if (DrawingOnBackground(x, y))
875 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
877 ClearRectangle(bitmap, x, y, width, height);
880 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
881 int src_x, int src_y, int width, int height,
882 int dst_x, int dst_y)
884 if (DrawingDeactivated(dst_x, dst_y, width, height))
887 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
888 dst_x, dst_y, BLIT_MASKED);
891 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
892 int src_x, int src_y, int width, int height,
893 int dst_x, int dst_y)
895 if (DrawingOnBackground(dst_x, dst_y))
897 /* draw background */
898 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
901 /* draw foreground */
902 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
906 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
910 void BlitTexture(Bitmap *bitmap,
911 int src_x, int src_y, int width, int height,
912 int dst_x, int dst_y)
917 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
921 void BlitTextureMasked(Bitmap *bitmap,
922 int src_x, int src_y, int width, int height,
923 int dst_x, int dst_y)
928 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
932 void BlitToScreen(Bitmap *bitmap,
933 int src_x, int src_y, int width, int height,
934 int dst_x, int dst_y)
939 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
940 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
941 width, height, dst_x, dst_y);
943 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
946 void BlitToScreenMasked(Bitmap *bitmap,
947 int src_x, int src_y, int width, int height,
948 int dst_x, int dst_y)
953 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
954 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
955 width, height, dst_x, dst_y);
957 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
960 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
963 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
966 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
969 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
972 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
973 int to_x, int to_y, Pixel pixel, int line_width)
977 if (program.headless)
980 for (x = 0; x < line_width; x++)
982 for (y = 0; y < line_width; y++)
984 int dx = x - line_width / 2;
985 int dy = y - line_width / 2;
987 if ((x == 0 && y == 0) ||
988 (x == 0 && y == line_width - 1) ||
989 (x == line_width - 1 && y == 0) ||
990 (x == line_width - 1 && y == line_width - 1))
994 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
999 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1004 for (i = 0; i < num_points - 1; i++)
1005 DrawLine(bitmap, points[i].x, points[i].y,
1006 points[i + 1].x, points[i + 1].y, pixel, line_width);
1009 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1013 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1015 if (program.headless)
1018 if (x < 0 || x >= bitmap->width ||
1019 y < 0 || y >= bitmap->height)
1022 return SDLGetPixel(bitmap, x, y);
1025 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1026 unsigned int color_g, unsigned int color_b)
1028 if (program.headless)
1031 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1034 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1036 unsigned int color_r = (color >> 16) & 0xff;
1037 unsigned int color_g = (color >> 8) & 0xff;
1038 unsigned int color_b = (color >> 0) & 0xff;
1040 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1043 void KeyboardAutoRepeatOn(void)
1045 #if defined(TARGET_SDL2)
1046 keyrepeat_status = TRUE;
1048 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1049 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1050 SDL_EnableUNICODE(1);
1054 void KeyboardAutoRepeatOff(void)
1056 #if defined(TARGET_SDL2)
1057 keyrepeat_status = FALSE;
1059 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1060 SDL_EnableUNICODE(0);
1064 boolean SetVideoMode(boolean fullscreen)
1066 return SDLSetVideoMode(fullscreen);
1069 void SetVideoFrameDelay(unsigned int frame_delay_value)
1071 video.frame_delay_value = frame_delay_value;
1074 unsigned int GetVideoFrameDelay()
1076 return video.frame_delay_value;
1079 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1081 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1082 (!fullscreen && video.fullscreen_enabled))
1083 fullscreen = SetVideoMode(fullscreen);
1088 Bitmap *LoadImage(char *filename)
1092 new_bitmap = SDLLoadImage(filename);
1095 new_bitmap->source_filename = getStringCopy(filename);
1100 Bitmap *LoadCustomImage(char *basename)
1102 char *filename = getCustomImageFilename(basename);
1105 if (filename == NULL)
1106 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1108 if ((new_bitmap = LoadImage(filename)) == NULL)
1109 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1114 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1116 char *filename = getCustomImageFilename(basename);
1119 if (filename == NULL) /* (should never happen) */
1121 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1125 if (strEqual(filename, bitmap->source_filename))
1127 /* The old and new image are the same (have the same filename and path).
1128 This usually means that this image does not exist in this graphic set
1129 and a fallback to the existing image is done. */
1134 if ((new_bitmap = LoadImage(filename)) == NULL)
1136 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1140 if (bitmap->width != new_bitmap->width ||
1141 bitmap->height != new_bitmap->height)
1143 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1145 FreeBitmap(new_bitmap);
1149 TransferBitmapPointers(new_bitmap, bitmap);
1153 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1155 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1158 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1160 if (bitmaps[IMG_BITMAP_CUSTOM])
1162 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1164 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1167 if (gfx.game_tile_size == gfx.standard_tile_size)
1169 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1174 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1175 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1176 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1178 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1180 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1181 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1184 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1185 int tile_size, boolean create_small_bitmaps)
1187 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1188 Bitmap *tmp_bitmap_final = NULL;
1189 Bitmap *tmp_bitmap_0 = NULL;
1190 Bitmap *tmp_bitmap_1 = NULL;
1191 Bitmap *tmp_bitmap_2 = NULL;
1192 Bitmap *tmp_bitmap_4 = NULL;
1193 Bitmap *tmp_bitmap_8 = NULL;
1194 Bitmap *tmp_bitmap_16 = NULL;
1195 Bitmap *tmp_bitmap_32 = NULL;
1196 int width_final, height_final;
1197 int width_0, height_0;
1198 int width_1, height_1;
1199 int width_2, height_2;
1200 int width_4, height_4;
1201 int width_8, height_8;
1202 int width_16, height_16;
1203 int width_32, height_32;
1204 int old_width, old_height;
1207 print_timestamp_init("CreateScaledBitmaps");
1209 old_width = old_bitmap->width;
1210 old_height = old_bitmap->height;
1212 /* calculate new image dimensions for final image size */
1213 width_final = old_width * zoom_factor;
1214 height_final = old_height * zoom_factor;
1216 /* get image with final size (this might require scaling up) */
1217 /* ("final" size may result in non-standard tile size image) */
1218 if (zoom_factor != 1)
1219 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1221 tmp_bitmap_final = old_bitmap;
1223 UPDATE_BUSY_STATE();
1225 width_0 = width_1 = width_final;
1226 height_0 = height_1 = height_final;
1228 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1230 if (create_small_bitmaps)
1232 /* check if we have a non-gameplay tile size image */
1233 if (tile_size != gfx.game_tile_size)
1235 /* get image with gameplay tile size */
1236 width_0 = width_final * gfx.game_tile_size / tile_size;
1237 height_0 = height_final * gfx.game_tile_size / tile_size;
1239 if (width_0 == old_width)
1240 tmp_bitmap_0 = old_bitmap;
1241 else if (width_0 == width_final)
1242 tmp_bitmap_0 = tmp_bitmap_final;
1244 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1246 UPDATE_BUSY_STATE();
1249 /* check if we have a non-standard tile size image */
1250 if (tile_size != gfx.standard_tile_size)
1252 /* get image with standard tile size */
1253 width_1 = width_final * gfx.standard_tile_size / tile_size;
1254 height_1 = height_final * gfx.standard_tile_size / tile_size;
1256 if (width_1 == old_width)
1257 tmp_bitmap_1 = old_bitmap;
1258 else if (width_1 == width_final)
1259 tmp_bitmap_1 = tmp_bitmap_final;
1260 else if (width_1 == width_0)
1261 tmp_bitmap_1 = tmp_bitmap_0;
1263 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1265 UPDATE_BUSY_STATE();
1268 /* calculate new image dimensions for small images */
1269 width_2 = width_1 / 2;
1270 height_2 = height_1 / 2;
1271 width_4 = width_1 / 4;
1272 height_4 = height_1 / 4;
1273 width_8 = width_1 / 8;
1274 height_8 = height_1 / 8;
1275 width_16 = width_1 / 16;
1276 height_16 = height_1 / 16;
1277 width_32 = width_1 / 32;
1278 height_32 = height_1 / 32;
1280 /* get image with 1/2 of normal size (for use in the level editor) */
1281 if (width_2 == old_width)
1282 tmp_bitmap_2 = old_bitmap;
1284 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1286 UPDATE_BUSY_STATE();
1288 /* get image with 1/4 of normal size (for use in the level editor) */
1289 if (width_4 == old_width)
1290 tmp_bitmap_4 = old_bitmap;
1292 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1294 UPDATE_BUSY_STATE();
1296 /* get image with 1/8 of normal size (for use on the preview screen) */
1297 if (width_8 == old_width)
1298 tmp_bitmap_8 = old_bitmap;
1300 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1302 UPDATE_BUSY_STATE();
1304 /* get image with 1/16 of normal size (for use on the preview screen) */
1305 if (width_16 == old_width)
1306 tmp_bitmap_16 = old_bitmap;
1308 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1310 UPDATE_BUSY_STATE();
1312 /* get image with 1/32 of normal size (for use on the preview screen) */
1313 if (width_32 == old_width)
1314 tmp_bitmap_32 = old_bitmap;
1316 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1318 UPDATE_BUSY_STATE();
1320 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1321 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1322 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1323 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1324 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1325 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1327 if (width_0 != width_1)
1328 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1330 if (bitmaps[IMG_BITMAP_CUSTOM])
1331 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1333 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1335 boolean free_old_bitmap = TRUE;
1337 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1338 if (bitmaps[i] == old_bitmap)
1339 free_old_bitmap = FALSE;
1341 if (free_old_bitmap)
1342 FreeBitmap(old_bitmap);
1346 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1349 UPDATE_BUSY_STATE();
1351 print_timestamp_done("CreateScaledBitmaps");
1354 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1357 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1360 void CreateBitmapTextures(Bitmap **bitmaps)
1362 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1365 void FreeBitmapTextures(Bitmap **bitmaps)
1367 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1370 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1372 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1376 /* ------------------------------------------------------------------------- */
1377 /* mouse pointer functions */
1378 /* ------------------------------------------------------------------------- */
1380 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1382 /* XPM image definitions */
1383 static const char *cursor_image_none[] =
1385 /* width height num_colors chars_per_pixel */
1415 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1416 static const char *cursor_image_dot[] =
1418 /* width height num_colors chars_per_pixel */
1447 static const char **cursor_image_playfield = cursor_image_dot;
1449 /* some people complained about a "white dot" on the screen and thought it
1450 was a graphical error... OK, let's just remove the whole pointer :-) */
1451 static const char **cursor_image_playfield = cursor_image_none;
1454 static const int cursor_bit_order = BIT_ORDER_MSB;
1456 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1458 struct MouseCursorInfo *cursor;
1459 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1460 int header_lines = 4;
1463 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1465 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1468 for (y = 0; y < cursor->width; y++)
1470 for (x = 0; x < cursor->height; x++)
1473 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1478 cursor->data[i] = cursor->mask[i] = 0;
1481 switch (image[header_lines + y][x])
1484 cursor->data[i] |= bit_mask;
1485 cursor->mask[i] |= bit_mask;
1489 cursor->mask[i] |= bit_mask;
1498 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1503 void SetMouseCursor(int mode)
1505 static struct MouseCursorInfo *cursor_none = NULL;
1506 static struct MouseCursorInfo *cursor_playfield = NULL;
1507 struct MouseCursorInfo *cursor_new;
1509 if (cursor_none == NULL)
1510 cursor_none = get_cursor_from_image(cursor_image_none);
1512 if (cursor_playfield == NULL)
1513 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1515 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1516 mode == CURSOR_NONE ? cursor_none :
1517 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1519 SDLSetMouseCursor(cursor_new);
1521 gfx.cursor_mode = mode;
1525 /* ========================================================================= */
1526 /* audio functions */
1527 /* ========================================================================= */
1529 void OpenAudio(void)
1531 /* always start with reliable default values */
1532 audio.sound_available = FALSE;
1533 audio.music_available = FALSE;
1534 audio.loops_available = FALSE;
1536 audio.sound_enabled = FALSE;
1537 audio.sound_deactivated = FALSE;
1539 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1540 audio.mixer_pid = 0;
1541 audio.device_name = NULL;
1542 audio.device_fd = -1;
1544 audio.num_channels = 0;
1545 audio.music_channel = 0;
1546 audio.first_sound_channel = 0;
1551 void CloseAudio(void)
1555 audio.sound_enabled = FALSE;
1558 void SetAudioMode(boolean enabled)
1560 if (!audio.sound_available)
1563 audio.sound_enabled = enabled;
1567 /* ========================================================================= */
1568 /* event functions */
1569 /* ========================================================================= */
1571 boolean PendingEvent(void)
1573 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1576 void WaitEvent(Event *event)
1578 SDLWaitEvent(event);
1581 void PeekEvent(Event *event)
1583 #if defined(TARGET_SDL2)
1584 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1586 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1590 void CheckQuitEvent(void)
1592 if (SDL_QuitRequested())
1593 program.exit_function(0);
1596 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1598 #if defined(TARGET_SDL2)
1599 /* key up/down events in SDL2 do not return text characters anymore */
1600 return event->keysym.sym;
1603 #if ENABLE_UNUSED_CODE
1604 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1605 (int)event->keysym.unicode,
1606 (int)event->keysym.sym,
1607 (int)SDL_GetModState());
1610 if (with_modifiers &&
1611 event->keysym.unicode > 0x0000 &&
1612 event->keysym.unicode < 0x2000)
1613 return event->keysym.unicode;
1615 return event->keysym.sym;
1620 KeyMod HandleKeyModState(Key key, int key_status)
1622 static KeyMod current_modifiers = KMOD_None;
1624 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1626 KeyMod new_modifier = KMOD_None;
1631 new_modifier = KMOD_Shift_L;
1634 new_modifier = KMOD_Shift_R;
1636 case KSYM_Control_L:
1637 new_modifier = KMOD_Control_L;
1639 case KSYM_Control_R:
1640 new_modifier = KMOD_Control_R;
1643 new_modifier = KMOD_Meta_L;
1646 new_modifier = KMOD_Meta_R;
1649 new_modifier = KMOD_Alt_L;
1652 new_modifier = KMOD_Alt_R;
1658 if (key_status == KEY_PRESSED)
1659 current_modifiers |= new_modifier;
1661 current_modifiers &= ~new_modifier;
1664 return current_modifiers;
1667 KeyMod GetKeyModState()
1669 return (KeyMod)SDL_GetModState();
1672 KeyMod GetKeyModStateFromEvents()
1674 /* always use key modifier state as tracked from key events (this is needed
1675 if the modifier key event was injected into the event queue, but the key
1676 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1677 query the keys as held pressed on the keyboard) -- this case is currently
1678 only used to filter out clipboard insert events from "True X-Mouse" tool */
1680 return HandleKeyModState(KSYM_UNDEFINED, 0);
1683 void StartTextInput(int x, int y, int width, int height)
1685 #if defined(TARGET_SDL2)
1686 #if defined(HAS_SCREEN_KEYBOARD)
1687 SDL_StartTextInput();
1689 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1691 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1692 video.shifted_up_delay = SDL_GetTicks();
1693 video.shifted_up = TRUE;
1699 void StopTextInput()
1701 #if defined(TARGET_SDL2)
1702 #if defined(HAS_SCREEN_KEYBOARD)
1703 SDL_StopTextInput();
1705 if (video.shifted_up)
1707 video.shifted_up_pos = 0;
1708 video.shifted_up_delay = SDL_GetTicks();
1709 video.shifted_up = FALSE;
1715 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1717 if (event->type != EVENT_CLIENTMESSAGE)
1720 return TRUE; /* the only possible message here is SDL_QUIT */
1724 /* ========================================================================= */
1725 /* joystick functions */
1726 /* ========================================================================= */
1728 void InitJoysticks()
1732 #if defined(NO_JOYSTICK)
1733 return; /* joysticks generally deactivated by compile-time directive */
1736 /* always start with reliable default values */
1737 joystick.status = JOYSTICK_NOT_AVAILABLE;
1738 for (i = 0; i < MAX_PLAYERS; i++)
1739 joystick.nr[i] = -1; /* no joystick configured */
1744 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1746 return SDLReadJoystick(nr, x, y, b1, b2);
1749 boolean CheckJoystickOpened(int nr)
1751 return SDLCheckJoystickOpened(nr);
1754 void ClearJoystickState()
1756 SDLClearJoystickState();