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 overlay.show_grid = FALSE;
333 #if defined(PLATFORM_ANDROID)
334 if (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS))
335 overlay.enabled = TRUE;
339 void SetTileCursorEnabled(boolean enabled)
341 tile_cursor.enabled = enabled;
344 void SetTileCursorActive(boolean active)
346 tile_cursor.active = active;
349 void SetTileCursorTargetXY(int x, int y)
351 // delayed placement of tile selection cursor at target position
352 // (tile cursor will be moved to target position step by step)
354 tile_cursor.xpos = x;
355 tile_cursor.ypos = y;
356 tile_cursor.target_x = tile_cursor.sx + x * gfx.game_tile_size;
357 tile_cursor.target_y = tile_cursor.sy + y * gfx.game_tile_size;
359 tile_cursor.moving = TRUE;
362 void SetTileCursorXY(int x, int y)
364 // immediate placement of tile selection cursor at target position
366 SetTileCursorTargetXY(x, y);
368 tile_cursor.x = tile_cursor.target_x;
369 tile_cursor.y = tile_cursor.target_y;
371 tile_cursor.moving = FALSE;
374 void SetTileCursorSXSY(int sx, int sy)
380 void SetOverlayEnabled(boolean enabled)
382 overlay.enabled = enabled;
385 void SetOverlayActive(boolean active)
387 overlay.active = active;
390 void SetOverlayShowGrid(boolean show_grid)
392 overlay.show_grid = show_grid;
394 SetOverlayActive(show_grid);
397 SetOverlayEnabled(TRUE);
400 boolean GetOverlayActive()
402 return overlay.active;
405 void SetDrawDeactivationMask(int draw_deactivation_mask)
407 gfx.draw_deactivation_mask = draw_deactivation_mask;
410 int GetDrawDeactivationMask()
412 return gfx.draw_deactivation_mask;
415 void SetDrawBackgroundMask(int draw_background_mask)
417 gfx.draw_background_mask = draw_background_mask;
420 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
422 if (background_bitmap_tile != NULL)
423 gfx.background_bitmap_mask |= mask;
425 gfx.background_bitmap_mask &= ~mask;
427 if (background_bitmap_tile == NULL) /* empty background requested */
430 if (mask == REDRAW_ALL)
431 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
432 0, 0, video.width, video.height);
433 else if (mask == REDRAW_FIELD)
434 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
435 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
436 else if (mask == REDRAW_DOOR_1)
437 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
438 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
441 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
443 /* remove every mask before setting mask for window */
444 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
445 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
446 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
449 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
451 /* remove window area mask before setting mask for main area */
452 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
453 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
454 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
457 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
459 /* remove window area mask before setting mask for door area */
460 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
461 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
462 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
466 /* ========================================================================= */
467 /* video functions */
468 /* ========================================================================= */
470 inline static int GetRealDepth(int depth)
472 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
475 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
476 int width, int height, Pixel color)
478 SDLFillRectangle(bitmap, x, y, width, height, color);
480 if (bitmap == backbuffer)
481 SetRedrawMaskFromArea(x, y, width, height);
484 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
485 int src_x, int src_y, int width, int height,
486 int dst_x, int dst_y, int mask_mode)
488 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
489 dst_x, dst_y, mask_mode);
491 if (dst_bitmap == backbuffer)
492 SetRedrawMaskFromArea(dst_x, dst_y, width, height);
495 void LimitScreenUpdates(boolean enable)
497 SDLLimitScreenUpdates(enable);
500 void InitVideoDefaults(void)
502 video.default_depth = 32;
505 void InitVideoDisplay(void)
507 if (program.headless)
510 SDLInitVideoDisplay();
511 #if defined(TARGET_SDL2)
516 void CloseVideoDisplay(void)
518 KeyboardAutoRepeatOn();
520 SDL_QuitSubSystem(SDL_INIT_VIDEO);
523 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
526 video.height = height;
527 video.depth = GetRealDepth(depth);
529 video.screen_width = width;
530 video.screen_height = height;
531 video.screen_xoffset = 0;
532 video.screen_yoffset = 0;
534 video.fullscreen_available = FULLSCREEN_STATUS;
535 video.fullscreen_enabled = FALSE;
537 video.window_scaling_available = WINDOW_SCALING_STATUS;
539 video.frame_delay = 0;
540 video.frame_delay_value = GAME_FRAME_DELAY;
542 video.shifted_up = FALSE;
543 video.shifted_up_pos = 0;
544 video.shifted_up_pos_last = 0;
545 video.shifted_up_delay = 0;
546 video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
548 SDLInitVideoBuffer(fullscreen);
550 video.initialized = !program.headless;
555 inline static void FreeBitmapPointers(Bitmap *bitmap)
560 SDLFreeBitmapPointers(bitmap);
562 checked_free(bitmap->source_filename);
563 bitmap->source_filename = NULL;
566 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
569 if (src_bitmap == NULL || dst_bitmap == NULL)
572 FreeBitmapPointers(dst_bitmap);
574 *dst_bitmap = *src_bitmap;
577 void FreeBitmap(Bitmap *bitmap)
582 FreeBitmapPointers(bitmap);
587 Bitmap *CreateBitmapStruct(void)
589 return checked_calloc(sizeof(Bitmap));
592 Bitmap *CreateBitmap(int width, int height, int depth)
594 Bitmap *new_bitmap = CreateBitmapStruct();
595 int real_width = MAX(1, width); /* prevent zero bitmap width */
596 int real_height = MAX(1, height); /* prevent zero bitmap height */
597 int real_depth = GetRealDepth(depth);
599 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
601 new_bitmap->width = real_width;
602 new_bitmap->height = real_height;
607 void ReCreateBitmap(Bitmap **bitmap, int width, int height)
611 /* if new bitmap size fits into old one, no need to re-create it */
612 if (width <= (*bitmap)->width &&
613 height <= (*bitmap)->height)
616 /* else adjust size so that old and new bitmap size fit into it */
617 width = MAX(width, (*bitmap)->width);
618 height = MAX(height, (*bitmap)->height);
621 Bitmap *new_bitmap = CreateBitmap(width, height, DEFAULT_DEPTH);
625 *bitmap = new_bitmap;
629 TransferBitmapPointers(new_bitmap, *bitmap);
634 void CloseWindow(DrawWindow *window)
638 void SetRedrawMaskFromArea(int x, int y, int width, int height)
642 int x2 = x + width - 1;
643 int y2 = y + height - 1;
645 if (width == 0 || height == 0)
648 if (IN_GFX_FIELD_FULL(x1, y1) && IN_GFX_FIELD_FULL(x2, y2))
649 redraw_mask |= REDRAW_FIELD;
650 else if (IN_GFX_DOOR_1(x1, y1) && IN_GFX_DOOR_1(x2, y2))
651 redraw_mask |= REDRAW_DOOR_1;
652 else if (IN_GFX_DOOR_2(x1, y1) && IN_GFX_DOOR_2(x2, y2))
653 redraw_mask |= REDRAW_DOOR_2;
654 else if (IN_GFX_DOOR_3(x1, y1) && IN_GFX_DOOR_3(x2, y2))
655 redraw_mask |= REDRAW_DOOR_3;
657 redraw_mask = REDRAW_ALL;
660 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
663 if (draw_mask == REDRAW_NONE)
666 if (draw_mask & REDRAW_ALL)
669 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
672 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
675 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
678 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
684 boolean DrawingDeactivatedField()
686 if (program.headless)
689 if (gfx.draw_deactivation_mask & REDRAW_FIELD)
695 boolean DrawingDeactivated(int x, int y, int width, int height)
697 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
700 boolean DrawingOnBackground(int x, int y)
702 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
703 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
706 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
707 int *width, int *height, boolean is_dest)
709 int clip_x, clip_y, clip_width, clip_height;
711 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
713 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
714 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
715 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
716 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
722 clip_width = bitmap->width;
723 clip_height = bitmap->height;
726 /* skip if rectangle completely outside bitmap */
728 if (*x + *width <= clip_x ||
729 *y + *height <= clip_y ||
730 *x >= clip_x + clip_width ||
731 *y >= clip_y + clip_height)
734 /* clip if rectangle overlaps bitmap */
738 *width -= clip_x - *x;
741 else if (*x + *width > clip_x + clip_width)
743 *width = clip_x + clip_width - *x;
748 *height -= clip_y - *y;
751 else if (*y + *height > clip_y + clip_height)
753 *height = clip_y + clip_height - *y;
759 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
760 int src_x, int src_y, int width, int height,
761 int dst_x, int dst_y)
763 int dst_x_unclipped = dst_x;
764 int dst_y_unclipped = dst_y;
766 if (program.headless)
769 if (src_bitmap == NULL || dst_bitmap == NULL)
772 if (DrawingDeactivated(dst_x, dst_y, width, height))
775 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
776 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
779 /* source x/y might need adjustment if destination x/y was clipped top/left */
780 src_x += dst_x - dst_x_unclipped;
781 src_y += dst_y - dst_y_unclipped;
783 #if defined(TARGET_SDL2)
784 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
785 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
786 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
787 but is already fixed in SVN and should therefore finally be fixed with
788 the next official SDL release, which is probably version 1.2.14.) */
789 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
791 if (src_bitmap == dst_bitmap)
793 /* needed when blitting directly to same bitmap -- should not be needed with
794 recent SDL libraries, but apparently does not work in 1.2.11 directly */
796 static Bitmap *tmp_bitmap = NULL;
797 static int tmp_bitmap_xsize = 0;
798 static int tmp_bitmap_ysize = 0;
800 /* start with largest static bitmaps for initial bitmap size ... */
801 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
803 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
804 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
807 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
808 if (src_bitmap->width > tmp_bitmap_xsize ||
809 src_bitmap->height > tmp_bitmap_ysize)
811 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
812 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
814 FreeBitmap(tmp_bitmap);
819 if (tmp_bitmap == NULL)
820 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
823 sysCopyArea(src_bitmap, tmp_bitmap,
824 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
825 sysCopyArea(tmp_bitmap, dst_bitmap,
826 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
832 sysCopyArea(src_bitmap, dst_bitmap,
833 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
836 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
837 int src_x, int src_y, int src_width, int src_height,
838 int dst_x, int dst_y, int dst_width, int dst_height)
840 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
841 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
842 int dst_xsize = dst_width;
843 int dst_ysize = dst_height;
844 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
845 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
848 for (y = 0; y < src_ysteps; y++)
850 for (x = 0; x < src_xsteps; x++)
852 int draw_x = dst_x + x * src_xsize;
853 int draw_y = dst_y + y * src_ysize;
854 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
855 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
857 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
863 void FadeRectangle(int x, int y, int width, int height,
864 int fade_mode, int fade_delay, int post_delay,
865 void (*draw_border_function)(void))
867 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
868 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
871 SDLFadeRectangle(x, y, width, height,
872 fade_mode, fade_delay, post_delay, draw_border_function);
875 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
878 if (DrawingDeactivated(x, y, width, height))
881 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
884 sysFillRectangle(bitmap, x, y, width, height, color);
887 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
889 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
892 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
893 int width, int height)
895 if (DrawingOnBackground(x, y))
896 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
898 ClearRectangle(bitmap, x, y, width, height);
901 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
902 int src_x, int src_y, int width, int height,
903 int dst_x, int dst_y)
905 if (DrawingDeactivated(dst_x, dst_y, width, height))
908 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
909 dst_x, dst_y, BLIT_MASKED);
912 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
913 int src_x, int src_y, int width, int height,
914 int dst_x, int dst_y)
916 if (DrawingOnBackground(dst_x, dst_y))
918 /* draw background */
919 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
922 /* draw foreground */
923 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
927 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
931 void BlitTexture(Bitmap *bitmap,
932 int src_x, int src_y, int width, int height,
933 int dst_x, int dst_y)
938 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
942 void BlitTextureMasked(Bitmap *bitmap,
943 int src_x, int src_y, int width, int height,
944 int dst_x, int dst_y)
949 SDLBlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y,
953 void BlitToScreen(Bitmap *bitmap,
954 int src_x, int src_y, int width, int height,
955 int dst_x, int dst_y)
960 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
961 BlitBitmap(bitmap, gfx.final_screen_bitmap, src_x, src_y,
962 width, height, dst_x, dst_y);
964 BlitTexture(bitmap, src_x, src_y, width, height, dst_x, dst_y);
967 void BlitToScreenMasked(Bitmap *bitmap,
968 int src_x, int src_y, int width, int height,
969 int dst_x, int dst_y)
974 if (video.screen_rendering_mode == SPECIAL_RENDERING_BITMAP)
975 BlitBitmapMasked(bitmap, gfx.final_screen_bitmap, src_x, src_y,
976 width, height, dst_x, dst_y);
978 BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
981 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
984 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
987 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
990 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
993 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
994 int to_x, int to_y, Pixel pixel, int line_width)
998 if (program.headless)
1001 for (x = 0; x < line_width; x++)
1003 for (y = 0; y < line_width; y++)
1005 int dx = x - line_width / 2;
1006 int dy = y - line_width / 2;
1008 if ((x == 0 && y == 0) ||
1009 (x == 0 && y == line_width - 1) ||
1010 (x == line_width - 1 && y == 0) ||
1011 (x == line_width - 1 && y == line_width - 1))
1015 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
1020 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
1025 for (i = 0; i < num_points - 1; i++)
1026 DrawLine(bitmap, points[i].x, points[i].y,
1027 points[i + 1].x, points[i + 1].y, pixel, line_width);
1030 SDLDrawLines(bitmap->surface, points, num_points, pixel);
1034 Pixel GetPixel(Bitmap *bitmap, int x, int y)
1036 if (program.headless)
1039 if (x < 0 || x >= bitmap->width ||
1040 y < 0 || y >= bitmap->height)
1043 return SDLGetPixel(bitmap, x, y);
1046 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
1047 unsigned int color_g, unsigned int color_b)
1049 if (program.headless)
1052 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
1055 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
1057 unsigned int color_r = (color >> 16) & 0xff;
1058 unsigned int color_g = (color >> 8) & 0xff;
1059 unsigned int color_b = (color >> 0) & 0xff;
1061 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
1064 void KeyboardAutoRepeatOn(void)
1066 #if defined(TARGET_SDL2)
1067 keyrepeat_status = TRUE;
1069 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
1070 SDL_DEFAULT_REPEAT_INTERVAL / 2);
1071 SDL_EnableUNICODE(1);
1075 void KeyboardAutoRepeatOff(void)
1077 #if defined(TARGET_SDL2)
1078 keyrepeat_status = FALSE;
1080 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1081 SDL_EnableUNICODE(0);
1085 boolean SetVideoMode(boolean fullscreen)
1087 return SDLSetVideoMode(fullscreen);
1090 void SetVideoFrameDelay(unsigned int frame_delay_value)
1092 video.frame_delay_value = frame_delay_value;
1095 unsigned int GetVideoFrameDelay()
1097 return video.frame_delay_value;
1100 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1102 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1103 (!fullscreen && video.fullscreen_enabled))
1104 fullscreen = SetVideoMode(fullscreen);
1109 Bitmap *LoadImage(char *filename)
1113 new_bitmap = SDLLoadImage(filename);
1116 new_bitmap->source_filename = getStringCopy(filename);
1121 Bitmap *LoadCustomImage(char *basename)
1123 char *filename = getCustomImageFilename(basename);
1126 if (filename == NULL)
1127 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1129 if ((new_bitmap = LoadImage(filename)) == NULL)
1130 Error(ERR_EXIT, "LoadImage('%s') failed: %s", basename, GetError());
1135 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1137 char *filename = getCustomImageFilename(basename);
1140 if (filename == NULL) /* (should never happen) */
1142 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1146 if (strEqual(filename, bitmap->source_filename))
1148 /* The old and new image are the same (have the same filename and path).
1149 This usually means that this image does not exist in this graphic set
1150 and a fallback to the existing image is done. */
1155 if ((new_bitmap = LoadImage(filename)) == NULL)
1157 Error(ERR_WARN, "LoadImage('%s') failed: %s", basename, GetError());
1161 if (bitmap->width != new_bitmap->width ||
1162 bitmap->height != new_bitmap->height)
1164 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1166 FreeBitmap(new_bitmap);
1170 TransferBitmapPointers(new_bitmap, bitmap);
1174 static Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1176 return SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1179 void ReCreateGameTileSizeBitmap(Bitmap **bitmaps)
1181 if (bitmaps[IMG_BITMAP_CUSTOM])
1183 FreeBitmap(bitmaps[IMG_BITMAP_CUSTOM]);
1185 bitmaps[IMG_BITMAP_CUSTOM] = NULL;
1188 if (gfx.game_tile_size == gfx.standard_tile_size)
1190 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1195 Bitmap *bitmap = bitmaps[IMG_BITMAP_STANDARD];
1196 int width = bitmap->width * gfx.game_tile_size / gfx.standard_tile_size;;
1197 int height = bitmap->height * gfx.game_tile_size / gfx.standard_tile_size;;
1199 Bitmap *bitmap_new = ZoomBitmap(bitmap, width, height);
1201 bitmaps[IMG_BITMAP_CUSTOM] = bitmap_new;
1202 bitmaps[IMG_BITMAP_GAME] = bitmap_new;
1205 static void CreateScaledBitmaps(Bitmap **bitmaps, int zoom_factor,
1206 int tile_size, boolean create_small_bitmaps)
1208 Bitmap *old_bitmap = bitmaps[IMG_BITMAP_STANDARD];
1209 Bitmap *tmp_bitmap_final = NULL;
1210 Bitmap *tmp_bitmap_0 = NULL;
1211 Bitmap *tmp_bitmap_1 = NULL;
1212 Bitmap *tmp_bitmap_2 = NULL;
1213 Bitmap *tmp_bitmap_4 = NULL;
1214 Bitmap *tmp_bitmap_8 = NULL;
1215 Bitmap *tmp_bitmap_16 = NULL;
1216 Bitmap *tmp_bitmap_32 = NULL;
1217 int width_final, height_final;
1218 int width_0, height_0;
1219 int width_1, height_1;
1220 int width_2, height_2;
1221 int width_4, height_4;
1222 int width_8, height_8;
1223 int width_16, height_16;
1224 int width_32, height_32;
1225 int old_width, old_height;
1228 print_timestamp_init("CreateScaledBitmaps");
1230 old_width = old_bitmap->width;
1231 old_height = old_bitmap->height;
1233 /* calculate new image dimensions for final image size */
1234 width_final = old_width * zoom_factor;
1235 height_final = old_height * zoom_factor;
1237 /* get image with final size (this might require scaling up) */
1238 /* ("final" size may result in non-standard tile size image) */
1239 if (zoom_factor != 1)
1240 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1242 tmp_bitmap_final = old_bitmap;
1244 UPDATE_BUSY_STATE();
1246 width_0 = width_1 = width_final;
1247 height_0 = height_1 = height_final;
1249 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1251 if (create_small_bitmaps)
1253 /* check if we have a non-gameplay tile size image */
1254 if (tile_size != gfx.game_tile_size)
1256 /* get image with gameplay tile size */
1257 width_0 = width_final * gfx.game_tile_size / tile_size;
1258 height_0 = height_final * gfx.game_tile_size / tile_size;
1260 if (width_0 == old_width)
1261 tmp_bitmap_0 = old_bitmap;
1262 else if (width_0 == width_final)
1263 tmp_bitmap_0 = tmp_bitmap_final;
1265 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1267 UPDATE_BUSY_STATE();
1270 /* check if we have a non-standard tile size image */
1271 if (tile_size != gfx.standard_tile_size)
1273 /* get image with standard tile size */
1274 width_1 = width_final * gfx.standard_tile_size / tile_size;
1275 height_1 = height_final * gfx.standard_tile_size / tile_size;
1277 if (width_1 == old_width)
1278 tmp_bitmap_1 = old_bitmap;
1279 else if (width_1 == width_final)
1280 tmp_bitmap_1 = tmp_bitmap_final;
1281 else if (width_1 == width_0)
1282 tmp_bitmap_1 = tmp_bitmap_0;
1284 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1286 UPDATE_BUSY_STATE();
1289 /* calculate new image dimensions for small images */
1290 width_2 = width_1 / 2;
1291 height_2 = height_1 / 2;
1292 width_4 = width_1 / 4;
1293 height_4 = height_1 / 4;
1294 width_8 = width_1 / 8;
1295 height_8 = height_1 / 8;
1296 width_16 = width_1 / 16;
1297 height_16 = height_1 / 16;
1298 width_32 = width_1 / 32;
1299 height_32 = height_1 / 32;
1301 /* get image with 1/2 of normal size (for use in the level editor) */
1302 if (width_2 == old_width)
1303 tmp_bitmap_2 = old_bitmap;
1305 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1307 UPDATE_BUSY_STATE();
1309 /* get image with 1/4 of normal size (for use in the level editor) */
1310 if (width_4 == old_width)
1311 tmp_bitmap_4 = old_bitmap;
1313 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1315 UPDATE_BUSY_STATE();
1317 /* get image with 1/8 of normal size (for use on the preview screen) */
1318 if (width_8 == old_width)
1319 tmp_bitmap_8 = old_bitmap;
1321 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1323 UPDATE_BUSY_STATE();
1325 /* get image with 1/16 of normal size (for use on the preview screen) */
1326 if (width_16 == old_width)
1327 tmp_bitmap_16 = old_bitmap;
1329 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1331 UPDATE_BUSY_STATE();
1333 /* get image with 1/32 of normal size (for use on the preview screen) */
1334 if (width_32 == old_width)
1335 tmp_bitmap_32 = old_bitmap;
1337 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1339 UPDATE_BUSY_STATE();
1341 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1342 bitmaps[IMG_BITMAP_16x16] = tmp_bitmap_2;
1343 bitmaps[IMG_BITMAP_8x8] = tmp_bitmap_4;
1344 bitmaps[IMG_BITMAP_4x4] = tmp_bitmap_8;
1345 bitmaps[IMG_BITMAP_2x2] = tmp_bitmap_16;
1346 bitmaps[IMG_BITMAP_1x1] = tmp_bitmap_32;
1348 if (width_0 != width_1)
1349 bitmaps[IMG_BITMAP_CUSTOM] = tmp_bitmap_0;
1351 if (bitmaps[IMG_BITMAP_CUSTOM])
1352 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_CUSTOM];
1354 bitmaps[IMG_BITMAP_GAME] = bitmaps[IMG_BITMAP_STANDARD];
1356 boolean free_old_bitmap = TRUE;
1358 for (i = 0; i < NUM_IMG_BITMAPS; i++)
1359 if (bitmaps[i] == old_bitmap)
1360 free_old_bitmap = FALSE;
1362 if (free_old_bitmap)
1363 FreeBitmap(old_bitmap);
1367 bitmaps[IMG_BITMAP_32x32] = tmp_bitmap_1;
1370 UPDATE_BUSY_STATE();
1372 print_timestamp_done("CreateScaledBitmaps");
1375 void CreateBitmapWithSmallBitmaps(Bitmap **bitmaps, int zoom_factor,
1378 CreateScaledBitmaps(bitmaps, zoom_factor, tile_size, TRUE);
1381 void CreateBitmapTextures(Bitmap **bitmaps)
1383 SDLCreateBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1386 void FreeBitmapTextures(Bitmap **bitmaps)
1388 SDLFreeBitmapTextures(bitmaps[IMG_BITMAP_STANDARD]);
1391 void ScaleBitmap(Bitmap **bitmaps, int zoom_factor)
1393 CreateScaledBitmaps(bitmaps, zoom_factor, 0, FALSE);
1397 /* ------------------------------------------------------------------------- */
1398 /* mouse pointer functions */
1399 /* ------------------------------------------------------------------------- */
1401 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1403 /* XPM image definitions */
1404 static const char *cursor_image_none[] =
1406 /* width height num_colors chars_per_pixel */
1436 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1437 static const char *cursor_image_dot[] =
1439 /* width height num_colors chars_per_pixel */
1468 static const char **cursor_image_playfield = cursor_image_dot;
1470 /* some people complained about a "white dot" on the screen and thought it
1471 was a graphical error... OK, let's just remove the whole pointer :-) */
1472 static const char **cursor_image_playfield = cursor_image_none;
1475 static const int cursor_bit_order = BIT_ORDER_MSB;
1477 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1479 struct MouseCursorInfo *cursor;
1480 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1481 int header_lines = 4;
1484 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1486 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1489 for (y = 0; y < cursor->width; y++)
1491 for (x = 0; x < cursor->height; x++)
1494 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1499 cursor->data[i] = cursor->mask[i] = 0;
1502 switch (image[header_lines + y][x])
1505 cursor->data[i] |= bit_mask;
1506 cursor->mask[i] |= bit_mask;
1510 cursor->mask[i] |= bit_mask;
1519 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1524 void SetMouseCursor(int mode)
1526 static struct MouseCursorInfo *cursor_none = NULL;
1527 static struct MouseCursorInfo *cursor_playfield = NULL;
1528 struct MouseCursorInfo *cursor_new;
1530 if (cursor_none == NULL)
1531 cursor_none = get_cursor_from_image(cursor_image_none);
1533 if (cursor_playfield == NULL)
1534 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1536 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1537 mode == CURSOR_NONE ? cursor_none :
1538 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1540 SDLSetMouseCursor(cursor_new);
1542 gfx.cursor_mode = mode;
1546 /* ========================================================================= */
1547 /* audio functions */
1548 /* ========================================================================= */
1550 void OpenAudio(void)
1552 /* always start with reliable default values */
1553 audio.sound_available = FALSE;
1554 audio.music_available = FALSE;
1555 audio.loops_available = FALSE;
1557 audio.sound_enabled = FALSE;
1558 audio.sound_deactivated = FALSE;
1560 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1561 audio.mixer_pid = 0;
1562 audio.device_name = NULL;
1563 audio.device_fd = -1;
1565 audio.num_channels = 0;
1566 audio.music_channel = 0;
1567 audio.first_sound_channel = 0;
1572 void CloseAudio(void)
1576 audio.sound_enabled = FALSE;
1579 void SetAudioMode(boolean enabled)
1581 if (!audio.sound_available)
1584 audio.sound_enabled = enabled;
1588 /* ========================================================================= */
1589 /* event functions */
1590 /* ========================================================================= */
1592 boolean PendingEvent(void)
1594 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1597 void WaitEvent(Event *event)
1599 SDLWaitEvent(event);
1602 void PeekEvent(Event *event)
1604 #if defined(TARGET_SDL2)
1605 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1607 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1611 void CheckQuitEvent(void)
1613 if (SDL_QuitRequested())
1614 program.exit_function(0);
1617 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1619 #if defined(TARGET_SDL2)
1620 /* key up/down events in SDL2 do not return text characters anymore */
1621 return event->keysym.sym;
1624 #if ENABLE_UNUSED_CODE
1625 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1626 (int)event->keysym.unicode,
1627 (int)event->keysym.sym,
1628 (int)SDL_GetModState());
1631 if (with_modifiers &&
1632 event->keysym.unicode > 0x0000 &&
1633 event->keysym.unicode < 0x2000)
1634 return event->keysym.unicode;
1636 return event->keysym.sym;
1641 KeyMod HandleKeyModState(Key key, int key_status)
1643 static KeyMod current_modifiers = KMOD_None;
1645 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1647 KeyMod new_modifier = KMOD_None;
1652 new_modifier = KMOD_Shift_L;
1655 new_modifier = KMOD_Shift_R;
1657 case KSYM_Control_L:
1658 new_modifier = KMOD_Control_L;
1660 case KSYM_Control_R:
1661 new_modifier = KMOD_Control_R;
1664 new_modifier = KMOD_Meta_L;
1667 new_modifier = KMOD_Meta_R;
1670 new_modifier = KMOD_Alt_L;
1673 new_modifier = KMOD_Alt_R;
1679 if (key_status == KEY_PRESSED)
1680 current_modifiers |= new_modifier;
1682 current_modifiers &= ~new_modifier;
1685 return current_modifiers;
1688 KeyMod GetKeyModState()
1690 return (KeyMod)SDL_GetModState();
1693 KeyMod GetKeyModStateFromEvents()
1695 /* always use key modifier state as tracked from key events (this is needed
1696 if the modifier key event was injected into the event queue, but the key
1697 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1698 query the keys as held pressed on the keyboard) -- this case is currently
1699 only used to filter out clipboard insert events from "True X-Mouse" tool */
1701 return HandleKeyModState(KSYM_UNDEFINED, 0);
1704 void StartTextInput(int x, int y, int width, int height)
1706 #if defined(TARGET_SDL2)
1707 #if defined(HAS_SCREEN_KEYBOARD)
1708 SDL_StartTextInput();
1710 if (y + height > SCREEN_KEYBOARD_POS(video.height))
1712 video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
1713 video.shifted_up_delay = SDL_GetTicks();
1714 video.shifted_up = TRUE;
1720 void StopTextInput()
1722 #if defined(TARGET_SDL2)
1723 #if defined(HAS_SCREEN_KEYBOARD)
1724 SDL_StopTextInput();
1726 if (video.shifted_up)
1728 video.shifted_up_pos = 0;
1729 video.shifted_up_delay = SDL_GetTicks();
1730 video.shifted_up = FALSE;
1736 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1738 if (event->type != EVENT_CLIENTMESSAGE)
1741 return TRUE; /* the only possible message here is SDL_QUIT */
1745 /* ========================================================================= */
1746 /* joystick functions */
1747 /* ========================================================================= */
1749 void InitJoysticks()
1753 #if defined(NO_JOYSTICK)
1754 return; /* joysticks generally deactivated by compile-time directive */
1757 /* always start with reliable default values */
1758 joystick.status = JOYSTICK_NOT_AVAILABLE;
1759 for (i = 0; i < MAX_PLAYERS; i++)
1760 joystick.nr[i] = -1; /* no joystick configured */
1765 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1767 return SDLReadJoystick(nr, x, y, b1, b2);
1770 boolean CheckJoystickOpened(int nr)
1772 return SDLCheckJoystickOpened(nr);
1775 void ClearJoystickState()
1777 SDLClearJoystickState();