1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
27 /* ========================================================================= */
28 /* exported variables */
29 /* ========================================================================= */
31 struct ProgramInfo program;
32 struct OptionInfo options;
33 struct VideoSystemInfo video;
34 struct AudioSystemInfo audio;
36 struct ArtworkInfo artwork;
37 struct JoystickInfo joystick;
38 struct SetupInfo setup;
40 LevelDirTree *leveldir_first_all = NULL;
41 LevelDirTree *leveldir_first = NULL;
42 LevelDirTree *leveldir_current = NULL;
45 struct LevelStats level_stats[MAX_LEVELS];
47 Display *display = NULL;
48 Visual *visual = NULL;
52 DrawWindow *window = NULL;
53 DrawBuffer *backbuffer = NULL;
54 DrawBuffer *drawto = NULL;
56 int button_status = MB_NOT_PRESSED;
57 boolean motion_status = FALSE;
58 #if defined(TARGET_SDL2)
59 boolean keyrepeat_status = TRUE;
62 int redraw_mask = REDRAW_NONE;
68 /* ========================================================================= */
69 /* init/close functions */
70 /* ========================================================================= */
72 void InitProgramInfo(char *argv0,
73 char *userdata_subdir, char *userdata_subdir_unix,
74 char *program_title, char *icon_title,
75 char *sdl_icon_filename, char *cookie_prefix,
78 program.command_basepath = getBasePath(argv0);
79 program.command_basename = getBaseName(argv0);
81 program.userdata_subdir = userdata_subdir;
82 program.userdata_subdir_unix = userdata_subdir_unix;
83 program.userdata_path = getUserGameDataDir();
85 program.program_title = program_title;
86 program.window_title = "(undefined)";
87 program.icon_title = icon_title;
89 program.sdl_icon_filename = sdl_icon_filename;
91 program.cookie_prefix = cookie_prefix;
93 program.version_major = VERSION_MAJOR(program_version);
94 program.version_minor = VERSION_MINOR(program_version);
95 program.version_patch = VERSION_PATCH(program_version);
96 program.version_build = VERSION_BUILD(program_version);
97 program.version_ident = program_version;
99 program.error_filename = getErrorFilename(ERROR_BASENAME);
100 program.error_file = stderr;
103 void SetWindowTitle()
105 program.window_title = program.window_title_function();
107 #if defined(TARGET_SDL)
112 void InitWindowTitleFunction(char *(*window_title_function)(void))
114 program.window_title_function = window_title_function;
117 void InitExitMessageFunction(void (*exit_message_function)(char *, va_list))
119 program.exit_message_function = exit_message_function;
122 void InitExitFunction(void (*exit_function)(int))
124 program.exit_function = exit_function;
126 /* set signal handlers to custom exit function */
127 signal(SIGINT, exit_function);
128 signal(SIGTERM, exit_function);
130 #if defined(TARGET_SDL)
131 /* set exit function to automatically cleanup SDL stuff after exit() */
136 void InitPlatformDependentStuff(void)
138 // this is initialized in GetOptions(), but may already be used before
139 options.verbose = TRUE;
141 #if defined(PLATFORM_MACOSX)
142 updateUserGameDataDir();
148 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
153 #if defined(TARGET_SDL)
154 #if defined(TARGET_SDL2)
155 int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
157 int sdl_init_flags = SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE;
160 if (SDL_Init(sdl_init_flags) < 0)
161 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
167 void ClosePlatformDependentStuff(void)
169 #if defined(PLATFORM_WIN32)
174 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
175 int real_sx, int real_sy,
176 int full_sxsize, int full_sysize,
177 Bitmap *field_save_buffer)
183 gfx.real_sx = real_sx;
184 gfx.real_sy = real_sy;
185 gfx.full_sxsize = full_sxsize;
186 gfx.full_sysize = full_sysize;
188 gfx.field_save_buffer = field_save_buffer;
191 gfx.background_bitmap = NULL;
192 gfx.background_bitmap_mask = REDRAW_NONE;
195 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
196 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
199 void InitGfxTileSizeInfo(int game_tile_size, int standard_tile_size)
201 gfx.game_tile_size = game_tile_size;
202 gfx.standard_tile_size = standard_tile_size;
205 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
213 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
221 void InitGfxDoor3Info(int ex, int ey, int exsize, int eysize)
229 void InitGfxWindowInfo(int win_xsize, int win_ysize)
231 gfx.win_xsize = win_xsize;
232 gfx.win_ysize = win_ysize;
235 gfx.background_bitmap_mask = REDRAW_NONE;
237 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
241 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
243 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
244 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
245 gfx.scrollbuffer_width = scrollbuffer_width;
246 gfx.scrollbuffer_height = scrollbuffer_height;
249 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
251 gfx.clipping_enabled = enabled;
254 gfx.clip_width = width;
255 gfx.clip_height = height;
258 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
260 gfx.draw_busy_anim_function = draw_busy_anim_function;
263 void InitGfxCustomArtworkInfo()
265 gfx.override_level_graphics = FALSE;
266 gfx.override_level_sounds = FALSE;
267 gfx.override_level_music = FALSE;
269 gfx.draw_init_text = TRUE;
272 void SetDrawDeactivationMask(int draw_deactivation_mask)
274 gfx.draw_deactivation_mask = draw_deactivation_mask;
277 void SetDrawBackgroundMask(int draw_background_mask)
279 gfx.draw_background_mask = draw_background_mask;
284 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
285 int dest_x, int dest_y, int width, int height)
287 int bitmap_xsize = width;
288 int bitmap_ysize = height;
289 int tile_xsize = tile->width;
290 int tile_ysize = tile->height;
291 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
292 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
295 for (y = 0; y < tile_ysteps; y++)
297 for (x = 0; x < tile_xsteps; x++)
299 int draw_x = dest_x + x * tile_xsize;
300 int draw_y = dest_y + y * tile_ysize;
301 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
302 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
304 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
309 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
311 if (background_bitmap_tile != NULL)
312 gfx.background_bitmap_mask |= mask;
314 gfx.background_bitmap_mask &= ~mask;
317 if (gfx.background_bitmap == NULL)
318 gfx.background_bitmap = CreateBitmap(video.width, video.height,
322 if (background_bitmap_tile == NULL) /* empty background requested */
325 if (mask == REDRAW_ALL)
326 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
327 0, 0, video.width, video.height);
328 else if (mask == REDRAW_FIELD)
329 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
330 gfx.real_sx, gfx.real_sy,
331 gfx.full_sxsize, gfx.full_sysize);
332 else if (mask == REDRAW_DOOR_1)
333 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
335 gfx.dxsize, gfx.dysize);
340 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
342 if (background_bitmap_tile != NULL)
343 gfx.background_bitmap_mask |= mask;
345 gfx.background_bitmap_mask &= ~mask;
348 if (gfx.background_bitmap == NULL)
349 gfx.background_bitmap = CreateBitmap(video.width, video.height,
353 if (background_bitmap_tile == NULL) /* empty background requested */
356 if (mask == REDRAW_ALL)
357 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
358 0, 0, video.width, video.height);
359 else if (mask == REDRAW_FIELD)
360 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
361 gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
362 else if (mask == REDRAW_DOOR_1)
363 BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
364 gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
369 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
371 /* remove every mask before setting mask for window */
372 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
373 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
374 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
377 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
379 /* remove window area mask before setting mask for main area */
380 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
381 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
382 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
385 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
387 /* remove window area mask before setting mask for door area */
388 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
389 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
390 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
394 /* ========================================================================= */
395 /* video functions */
396 /* ========================================================================= */
398 inline static int GetRealDepth(int depth)
400 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
403 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
404 int width, int height, Pixel color)
406 SDLFillRectangle(bitmap, x, y, width, height, color);
409 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
410 int src_x, int src_y, int width, int height,
411 int dst_x, int dst_y, int mask_mode)
413 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
414 dst_x, dst_y, mask_mode);
417 void LimitScreenUpdates(boolean enable)
419 #if defined(TARGET_SDL)
420 SDLLimitScreenUpdates(enable);
424 void InitVideoDisplay(void)
426 SDLInitVideoDisplay();
429 void CloseVideoDisplay(void)
431 KeyboardAutoRepeatOn();
433 #if defined(TARGET_SDL)
434 SDL_QuitSubSystem(SDL_INIT_VIDEO);
437 XCloseDisplay(display);
441 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
444 printf("::: InitVideoBuffer\n");
448 video.height = height;
449 video.depth = GetRealDepth(depth);
451 video.fullscreen_available = FULLSCREEN_STATUS;
452 video.fullscreen_enabled = FALSE;
453 // video.fullscreen_initial = FALSE;
455 video.fullscreen_mode_current = NULL;
456 video.fullscreen_modes = NULL;
459 video.window_scaling_available = WINDOW_SCALING_STATUS;
461 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
466 inline static void FreeBitmapPointers(Bitmap *bitmap)
471 SDLFreeBitmapPointers(bitmap);
473 checked_free(bitmap->source_filename);
474 bitmap->source_filename = NULL;
477 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
480 if (src_bitmap == NULL || dst_bitmap == NULL)
483 FreeBitmapPointers(dst_bitmap);
485 *dst_bitmap = *src_bitmap;
488 void FreeBitmap(Bitmap *bitmap)
493 FreeBitmapPointers(bitmap);
498 Bitmap *CreateBitmapStruct(void)
500 return checked_calloc(sizeof(struct SDLSurfaceInfo));
503 Bitmap *CreateBitmap(int width, int height, int depth)
505 Bitmap *new_bitmap = CreateBitmapStruct();
506 int real_width = MAX(1, width); /* prevent zero bitmap width */
507 int real_height = MAX(1, height); /* prevent zero bitmap height */
508 int real_depth = GetRealDepth(depth);
510 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
512 new_bitmap->width = real_width;
513 new_bitmap->height = real_height;
518 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
520 Bitmap *new_bitmap = CreateBitmap(width, height, depth);
524 *bitmap = new_bitmap;
528 TransferBitmapPointers(new_bitmap, *bitmap);
533 void CloseWindow(DrawWindow *window)
537 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
540 if (draw_mask == REDRAW_NONE)
543 if (draw_mask & REDRAW_ALL)
547 if ((draw_mask & REDRAW_FIELD) && IN_GFX_FIELD_FULL(x, y))
550 if ((draw_mask & REDRAW_DOOR_1) && IN_GFX_DOOR_1(x, y))
553 if ((draw_mask & REDRAW_DOOR_2) && IN_GFX_DOOR_2(x, y))
556 if ((draw_mask & REDRAW_DOOR_3) && IN_GFX_DOOR_3(x, y))
559 if ((draw_mask & REDRAW_FIELD) &&
560 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
563 if ((draw_mask & REDRAW_DOOR_1) &&
564 x >= gfx.dx && y < gfx.dy + gfx.dysize)
567 if ((draw_mask & REDRAW_DOOR_2) &&
568 x >= gfx.dx && y >= gfx.vy)
575 boolean DrawingDeactivated(int x, int y, int width, int height)
577 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
580 boolean DrawingOnBackground(int x, int y)
582 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
583 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
586 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
587 int *width, int *height, boolean is_dest)
590 int clip_x, clip_y, clip_width, clip_height;
592 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
594 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
595 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
596 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
597 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
603 clip_width = bitmap->width;
604 clip_height = bitmap->height;
607 /* skip if rectangle completely outside bitmap */
609 if (*x + *width <= clip_x ||
610 *y + *height <= clip_y ||
611 *x >= clip_x + clip_width ||
612 *y >= clip_y + clip_height)
615 /* clip if rectangle overlaps bitmap */
619 *width -= clip_x - *x;
622 else if (*x + *width > clip_x + clip_width)
624 *width = clip_x + clip_width - *x;
629 *height -= clip_y - *y;
632 else if (*y + *height > clip_y + clip_height)
634 *height = clip_y + clip_height - *y;
641 /* skip if rectangle completely outside bitmap */
643 if (*x + *width <= 0 ||
645 *x >= bitmap->width ||
646 *y >= bitmap->height)
649 /* clip if rectangle overlaps bitmap */
656 else if (*x + *width > bitmap->width)
658 *width = bitmap->width - *x;
666 else if (*y + *height > bitmap->height)
668 *height = bitmap->height - *y;
675 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
676 int src_x, int src_y, int width, int height,
677 int dst_x, int dst_y)
679 int dst_x_unclipped = dst_x;
680 int dst_y_unclipped = dst_y;
682 if (src_bitmap == NULL || dst_bitmap == NULL)
685 if (DrawingDeactivated(dst_x, dst_y, width, height))
689 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
690 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
693 /* source x/y might need adjustment if destination x/y was clipped top/left */
694 src_x += dst_x - dst_x_unclipped;
695 src_y += dst_y - dst_y_unclipped;
698 /* skip if rectangle starts outside bitmap */
699 if (src_x >= src_bitmap->width ||
700 src_y >= src_bitmap->height ||
701 dst_x >= dst_bitmap->width ||
702 dst_y >= dst_bitmap->height)
705 /* clip if rectangle overlaps bitmap */
706 if (src_x + width > src_bitmap->width)
707 width = src_bitmap->width - src_x;
708 if (src_y + height > src_bitmap->height)
709 height = src_bitmap->height - src_y;
710 if (dst_x + width > dst_bitmap->width)
711 width = dst_bitmap->width - dst_x;
712 if (dst_y + height > dst_bitmap->height)
713 height = dst_bitmap->height - dst_y;
717 /* !!! 2013-12-11: An "old friend" is back. Same bug in SDL2 2.0.1 !!! */
719 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
720 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
721 but is already fixed in SVN and should therefore finally be fixed with
722 the next official SDL release, which is probably version 1.2.14.) */
724 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
725 //#if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
726 #if defined(TARGET_SDL2)
727 if (src_bitmap == dst_bitmap)
729 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
731 /* needed when blitting directly to same bitmap -- should not be needed with
732 recent SDL libraries, but apparently does not work in 1.2.11 directly */
734 static Bitmap *tmp_bitmap = NULL;
735 static int tmp_bitmap_xsize = 0;
736 static int tmp_bitmap_ysize = 0;
738 /* start with largest static bitmaps for initial bitmap size ... */
739 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
741 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
742 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
745 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
746 if (src_bitmap->width > tmp_bitmap_xsize ||
747 src_bitmap->height > tmp_bitmap_ysize)
749 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
750 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
752 FreeBitmap(tmp_bitmap);
757 if (tmp_bitmap == NULL)
758 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
761 sysCopyArea(src_bitmap, tmp_bitmap,
762 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
763 sysCopyArea(tmp_bitmap, dst_bitmap,
764 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
774 if (dst_x < gfx.sx + gfx.sxsize)
775 printf("::: %d: BlitBitmap(%d, %d, %d, %d)\n",
776 FrameCounter, dst_x, dst_y, width, height);
779 sysCopyArea(src_bitmap, dst_bitmap,
780 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
783 void BlitBitmapTiled(Bitmap *src_bitmap, Bitmap *dst_bitmap,
784 int src_x, int src_y, int src_width, int src_height,
785 int dst_x, int dst_y, int dst_width, int dst_height)
787 int src_xsize = (src_width == 0 ? src_bitmap->width : src_width);
788 int src_ysize = (src_height == 0 ? src_bitmap->height : src_height);
789 int dst_xsize = dst_width;
790 int dst_ysize = dst_height;
791 int src_xsteps = (dst_xsize + src_xsize - 1) / src_xsize;
792 int src_ysteps = (dst_ysize + src_ysize - 1) / src_ysize;
795 for (y = 0; y < src_ysteps; y++)
797 for (x = 0; x < src_xsteps; x++)
799 int draw_x = dst_x + x * src_xsize;
800 int draw_y = dst_y + y * src_ysize;
801 int draw_xsize = MIN(src_xsize, dst_xsize - x * src_xsize);
802 int draw_ysize = MIN(src_ysize, dst_ysize - y * src_ysize);
804 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, draw_xsize, draw_ysize,
810 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
811 int fade_mode, int fade_delay, int post_delay,
812 void (*draw_border_function)(void))
815 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
816 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
820 SDLFadeRectangle(bitmap_cross, x, y, width, height,
821 fade_mode, fade_delay, post_delay, draw_border_function);
824 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
827 if (DrawingDeactivated(x, y, width, height))
831 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
834 /* skip if rectangle starts outside bitmap */
835 if (x >= bitmap->width ||
839 /* clip if rectangle overlaps bitmap */
840 if (x + width > bitmap->width)
841 width = bitmap->width - x;
842 if (y + height > bitmap->height)
843 height = bitmap->height - y;
846 sysFillRectangle(bitmap, x, y, width, height, color);
849 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
851 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
854 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
855 int width, int height)
857 if (DrawingOnBackground(x, y))
858 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
860 ClearRectangle(bitmap, x, y, width, height);
863 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
867 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
871 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
872 int src_x, int src_y, int width, int height,
873 int dst_x, int dst_y)
875 if (DrawingDeactivated(dst_x, dst_y, width, height))
878 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
879 dst_x, dst_y, BLIT_MASKED);
882 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
883 int src_x, int src_y, int width, int height,
884 int dst_x, int dst_y)
886 if (DrawingOnBackground(dst_x, dst_y))
888 /* draw background */
889 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
892 /* draw foreground */
893 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
894 dst_x - src_x, dst_y - src_y);
895 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
899 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
903 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
906 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
909 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
912 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
915 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
916 int to_x, int to_y, Pixel pixel, int line_width)
920 for (x = 0; x < line_width; x++)
922 for (y = 0; y < line_width; y++)
924 int dx = x - line_width / 2;
925 int dy = y - line_width / 2;
927 if ((x == 0 && y == 0) ||
928 (x == 0 && y == line_width - 1) ||
929 (x == line_width - 1 && y == 0) ||
930 (x == line_width - 1 && y == line_width - 1))
934 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
939 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
944 for (i = 0; i < num_points - 1; i++)
945 DrawLine(bitmap, points[i].x, points[i].y,
946 points[i + 1].x, points[i + 1].y, pixel, line_width);
949 SDLDrawLines(bitmap->surface, points, num_points, pixel);
953 Pixel GetPixel(Bitmap *bitmap, int x, int y)
955 if (x < 0 || x >= bitmap->width ||
956 y < 0 || y >= bitmap->height)
959 return SDLGetPixel(bitmap, x, y);
962 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
963 unsigned int color_g, unsigned int color_b)
965 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
968 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
970 unsigned int color_r = (color >> 16) & 0xff;
971 unsigned int color_g = (color >> 8) & 0xff;
972 unsigned int color_b = (color >> 0) & 0xff;
974 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
977 /* execute all pending screen drawing operations */
978 void FlushDisplay(void)
982 /* execute and wait for all pending screen drawing operations */
983 void SyncDisplay(void)
987 void KeyboardAutoRepeatOn(void)
989 #if defined(TARGET_SDL)
990 #if defined(TARGET_SDL2)
991 keyrepeat_status = TRUE;
993 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
994 SDL_DEFAULT_REPEAT_INTERVAL / 2);
995 SDL_EnableUNICODE(1);
999 XAutoRepeatOn(display);
1003 void KeyboardAutoRepeatOff(void)
1005 #if defined(TARGET_SDL)
1006 #if defined(TARGET_SDL2)
1007 keyrepeat_status = FALSE;
1009 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1010 SDL_EnableUNICODE(0);
1014 XAutoRepeatOff(display);
1018 boolean PointerInWindow(DrawWindow *window)
1020 #if defined(TARGET_SDL)
1028 /* if XQueryPointer() returns False, the pointer
1029 is not on the same screen as the specified window */
1030 return XQueryPointer(display, window->drawable, &root, &child,
1031 &root_x, &root_y, &win_x, &win_y, &mask);
1035 boolean SetVideoMode(boolean fullscreen)
1037 return SDLSetVideoMode(&backbuffer, fullscreen);
1040 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1042 #if defined(TARGET_SDL)
1043 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1044 (!fullscreen && video.fullscreen_enabled))
1045 fullscreen = SetVideoMode(fullscreen);
1051 Bitmap *LoadImage(char *filename)
1055 new_bitmap = SDLLoadImage(filename);
1058 new_bitmap->source_filename = getStringCopy(filename);
1063 Bitmap *LoadCustomImage(char *basename)
1065 char *filename = getCustomImageFilename(basename);
1068 if (filename == NULL)
1069 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1071 if ((new_bitmap = LoadImage(filename)) == NULL)
1072 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1077 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1079 char *filename = getCustomImageFilename(basename);
1082 if (filename == NULL) /* (should never happen) */
1084 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1088 if (strEqual(filename, bitmap->source_filename))
1090 /* The old and new image are the same (have the same filename and path).
1091 This usually means that this image does not exist in this graphic set
1092 and a fallback to the existing image is done. */
1097 if ((new_bitmap = LoadImage(filename)) == NULL)
1099 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1103 if (bitmap->width != new_bitmap->width ||
1104 bitmap->height != new_bitmap->height)
1106 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1108 FreeBitmap(new_bitmap);
1112 TransferBitmapPointers(new_bitmap, bitmap);
1116 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1119 // !!! TEST ONLY !!!
1121 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1122 print_timestamp_time("CreateBitmap");
1124 SDL_Rect src_rect, dst_rect;
1128 src_rect.w = src_bitmap->width - 0;
1129 src_rect.h = src_bitmap->height;
1133 dst_rect.w = dst_bitmap->width;
1134 dst_rect.h = dst_bitmap->height;
1136 SDL_BlitScaled(src_bitmap->surface, &src_rect,
1137 dst_bitmap->surface, &dst_rect);
1138 print_timestamp_time("SDL_BlitScaled");
1142 Bitmap *dst_bitmap = SDLZoomBitmap(src_bitmap, zoom_width, zoom_height);
1148 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1149 int tile_size, boolean create_small_bitmaps)
1153 Bitmap *tmp_bitmap_final = NULL;
1154 Bitmap *tmp_bitmap_0 = NULL;
1155 Bitmap *tmp_bitmap_1 = NULL;
1156 Bitmap *tmp_bitmap_2 = NULL;
1157 Bitmap *tmp_bitmap_4 = NULL;
1158 Bitmap *tmp_bitmap_8 = NULL;
1159 Bitmap *tmp_bitmap_16 = NULL;
1160 Bitmap *tmp_bitmap_32 = NULL;
1161 int width_final, height_final;
1162 int width_0, height_0;
1163 int width_1, height_1;
1164 int width_2, height_2;
1165 int width_4, height_4;
1166 int width_8, height_8;
1167 int width_16, height_16;
1169 int width_32, height_32;
1171 int old_width, old_height;
1172 int new_width, new_height;
1174 print_timestamp_init("CreateScaledBitmaps");
1176 old_width = old_bitmap->width;
1177 old_height = old_bitmap->height;
1180 /* calculate new image dimensions for final image size */
1181 width_final = old_width * zoom_factor;
1182 height_final = old_height * zoom_factor;
1184 /* get image with final size (this might require scaling up) */
1185 /* ("final" size may result in non-standard tile size image) */
1186 if (zoom_factor != 1)
1187 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1189 tmp_bitmap_final = old_bitmap;
1193 /* calculate new image dimensions for final image size */
1194 width_1 = old_width * zoom_factor;
1195 height_1 = old_height * zoom_factor;
1197 /* get image with final size (this might require scaling up) */
1198 /* ("final" size may result in non-standard tile size image) */
1199 if (zoom_factor != 1)
1200 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1202 tmp_bitmap_1 = old_bitmap;
1205 UPDATE_BUSY_STATE();
1207 width_0 = width_1 = width_final;
1208 height_0 = height_1 = height_final;
1210 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1213 if (create_small_bitmaps)
1215 /* check if we have a non-gameplay tile size image */
1216 if (tile_size != gfx.game_tile_size)
1218 /* get image with gameplay tile size */
1219 width_0 = width_final * gfx.game_tile_size / tile_size;
1220 height_0 = height_final * gfx.game_tile_size / tile_size;
1222 if (width_0 == old_width)
1223 tmp_bitmap_0 = old_bitmap;
1224 else if (width_0 == width_final)
1225 tmp_bitmap_0 = tmp_bitmap_final;
1229 if (old_width != width_0)
1230 printf("::: %d, %d -> %d, %d\n",
1231 old_width, old_height, width_0, height_0);
1234 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1237 UPDATE_BUSY_STATE();
1240 /* check if we have a non-standard tile size image */
1241 if (tile_size != gfx.standard_tile_size)
1243 /* get image with standard tile size */
1244 width_1 = width_final * gfx.standard_tile_size / tile_size;
1245 height_1 = height_final * gfx.standard_tile_size / tile_size;
1247 if (width_1 == old_width)
1248 tmp_bitmap_1 = old_bitmap;
1249 else if (width_1 == width_final)
1250 tmp_bitmap_1 = tmp_bitmap_final;
1251 else if (width_1 == width_0)
1252 tmp_bitmap_1 = tmp_bitmap_0;
1254 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1256 UPDATE_BUSY_STATE();
1261 if (create_small_bitmaps)
1263 /* calculate new image dimensions for small images */
1264 width_2 = width_1 / 2;
1265 height_2 = height_1 / 2;
1266 width_4 = width_1 / 4;
1267 height_4 = height_1 / 4;
1268 width_8 = width_1 / 8;
1269 height_8 = height_1 / 8;
1270 width_16 = width_1 / 16;
1271 height_16 = height_1 / 16;
1273 width_32 = width_1 / 32;
1274 height_32 = height_1 / 32;
1278 /* get image with 1/2 of normal size (for use in the level editor) */
1279 if (width_2 == old_width)
1280 tmp_bitmap_2 = old_bitmap;
1282 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1284 UPDATE_BUSY_STATE();
1286 /* get image with 1/4 of normal size (for use in the level editor) */
1287 if (width_4 == old_width)
1288 tmp_bitmap_4 = old_bitmap;
1290 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1292 UPDATE_BUSY_STATE();
1294 /* get image with 1/8 of normal size (for use on the preview screen) */
1295 if (width_8 == old_width)
1296 tmp_bitmap_8 = old_bitmap;
1298 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1300 UPDATE_BUSY_STATE();
1302 /* get image with 1/16 of normal size (for use on the preview screen) */
1303 if (width_16 == old_width)
1304 tmp_bitmap_16 = old_bitmap;
1306 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1308 UPDATE_BUSY_STATE();
1310 /* get image with 1/32 of normal size (for use on the preview screen) */
1311 if (width_32 == old_width)
1312 tmp_bitmap_32 = old_bitmap;
1314 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1316 UPDATE_BUSY_STATE();
1320 /* get image with 1/2 of normal size (for use in the level editor) */
1321 if (zoom_factor != 2)
1322 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1324 tmp_bitmap_2 = old_bitmap;
1326 UPDATE_BUSY_STATE();
1328 /* get image with 1/4 of normal size (for use in the level editor) */
1329 if (zoom_factor != 4)
1330 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1332 tmp_bitmap_4 = old_bitmap;
1334 UPDATE_BUSY_STATE();
1336 /* get image with 1/8 of normal size (for use on the preview screen) */
1337 if (zoom_factor != 8)
1338 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1340 tmp_bitmap_8 = old_bitmap;
1342 UPDATE_BUSY_STATE();
1344 /* get image with 1/16 of normal size (for use on the preview screen) */
1345 if (zoom_factor != 16)
1346 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1348 tmp_bitmap_16 = old_bitmap;
1350 UPDATE_BUSY_STATE();
1352 /* get image with 1/32 of normal size (for use on the preview screen) */
1353 if (zoom_factor != 32)
1354 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1356 tmp_bitmap_32 = old_bitmap;
1358 UPDATE_BUSY_STATE();
1363 /* if image was scaled up, create new clipmask for normal size image */
1364 if (zoom_factor != 1)
1366 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1368 if (old_bitmap->surface_masked)
1369 SDL_FreeSurface(old_bitmap->surface_masked);
1371 SDL_SetColorKey(tmp_surface_1, SET_TRANSPARENT_PIXEL,
1372 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1373 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1374 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1375 SDL_SetColorKey(tmp_surface_1, UNSET_TRANSPARENT_PIXEL, 0);
1379 if (create_small_bitmaps)
1381 new_width = width_1;
1382 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1385 if (width_0 != width_1)
1387 new_width += width_0;
1388 new_height = MAX(new_height, height_0);
1392 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1395 if (width_0 != width_1)
1396 BlitBitmap(tmp_bitmap_0, new_bitmap, 0, 0, width_0, height_0, width_1, 0);
1399 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1400 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1402 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1403 width_1 / 2, height_1);
1404 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1405 3 * width_1 / 4, height_1);
1406 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1407 7 * width_1 / 8, height_1);
1408 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1409 15 * width_1 / 16, height_1);
1411 UPDATE_BUSY_STATE();
1415 new_width = width_1;
1416 new_height = height_1;
1418 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1421 if (create_small_bitmaps)
1423 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1426 if (tmp_bitmap_final != old_bitmap)
1427 FreeBitmap(tmp_bitmap_final);
1429 if (tmp_bitmap_0 != old_bitmap &&
1430 tmp_bitmap_0 != tmp_bitmap_final)
1431 FreeBitmap(tmp_bitmap_0);
1433 if (tmp_bitmap_1 != old_bitmap &&
1434 tmp_bitmap_1 != tmp_bitmap_final &&
1435 tmp_bitmap_1 != tmp_bitmap_0)
1436 FreeBitmap(tmp_bitmap_1);
1438 if (tmp_bitmap_2 != old_bitmap)
1439 FreeBitmap(tmp_bitmap_2);
1441 if (tmp_bitmap_4 != old_bitmap)
1442 FreeBitmap(tmp_bitmap_4);
1444 if (tmp_bitmap_8 != old_bitmap)
1445 FreeBitmap(tmp_bitmap_8);
1447 if (tmp_bitmap_16 != old_bitmap)
1448 FreeBitmap(tmp_bitmap_16);
1450 if (tmp_bitmap_32 != old_bitmap)
1451 FreeBitmap(tmp_bitmap_32);
1455 if (zoom_factor != 1)
1456 FreeBitmap(tmp_bitmap_1);
1458 if (zoom_factor != 2)
1459 FreeBitmap(tmp_bitmap_2);
1461 if (zoom_factor != 4)
1462 FreeBitmap(tmp_bitmap_4);
1464 if (zoom_factor != 8)
1465 FreeBitmap(tmp_bitmap_8);
1467 if (zoom_factor != 16)
1468 FreeBitmap(tmp_bitmap_16);
1470 if (zoom_factor != 32)
1471 FreeBitmap(tmp_bitmap_32);
1475 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1476 #if defined(TARGET_SDL)
1477 swap_bitmap.surface = old_bitmap->surface;
1478 old_bitmap->surface = new_bitmap->surface;
1479 new_bitmap->surface = swap_bitmap.surface;
1481 swap_bitmap.drawable = old_bitmap->drawable;
1482 old_bitmap->drawable = new_bitmap->drawable;
1483 new_bitmap->drawable = swap_bitmap.drawable;
1486 old_bitmap->width = new_bitmap->width;
1487 old_bitmap->height = new_bitmap->height;
1490 /* this replaces all blit masks created when loading -- maybe optimize this */
1492 SDL_Surface *old_surface = old_bitmap->surface;
1494 if (old_bitmap->surface_masked)
1495 SDL_FreeSurface(old_bitmap->surface_masked);
1497 SDL_SetColorKey(old_surface, SET_TRANSPARENT_PIXEL,
1498 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1501 if ((old_bitmap->surface_masked = SDLGetNativeSurface(old_surface)) == NULL)
1502 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1504 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) == NULL)
1505 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1508 SDL_SetColorKey(old_surface, UNSET_TRANSPARENT_PIXEL, 0);
1512 UPDATE_BUSY_STATE();
1514 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1516 print_timestamp_done("CreateScaledBitmaps");
1519 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor,
1522 CreateScaledBitmaps(old_bitmap, zoom_factor, tile_size, TRUE);
1525 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1527 CreateScaledBitmaps(old_bitmap, zoom_factor, 0, FALSE);
1531 /* ------------------------------------------------------------------------- */
1532 /* mouse pointer functions */
1533 /* ------------------------------------------------------------------------- */
1535 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1537 /* XPM image definitions */
1538 static const char *cursor_image_none[] =
1540 /* width height num_colors chars_per_pixel */
1570 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1571 static const char *cursor_image_dot[] =
1573 /* width height num_colors chars_per_pixel */
1602 static const char **cursor_image_playfield = cursor_image_dot;
1604 /* some people complained about a "white dot" on the screen and thought it
1605 was a graphical error... OK, let's just remove the whole pointer :-) */
1606 static const char **cursor_image_playfield = cursor_image_none;
1609 static const int cursor_bit_order = BIT_ORDER_MSB;
1611 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1613 struct MouseCursorInfo *cursor;
1614 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1615 int header_lines = 4;
1618 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1620 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1623 for (y = 0; y < cursor->width; y++)
1625 for (x = 0; x < cursor->height; x++)
1628 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1633 cursor->data[i] = cursor->mask[i] = 0;
1636 switch (image[header_lines + y][x])
1639 cursor->data[i] |= bit_mask;
1640 cursor->mask[i] |= bit_mask;
1644 cursor->mask[i] |= bit_mask;
1653 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1658 void SetMouseCursor(int mode)
1660 static struct MouseCursorInfo *cursor_none = NULL;
1661 static struct MouseCursorInfo *cursor_playfield = NULL;
1662 struct MouseCursorInfo *cursor_new;
1664 if (cursor_none == NULL)
1665 cursor_none = get_cursor_from_image(cursor_image_none);
1667 if (cursor_playfield == NULL)
1668 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1670 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1671 mode == CURSOR_NONE ? cursor_none :
1672 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1674 SDLSetMouseCursor(cursor_new);
1678 /* ========================================================================= */
1679 /* audio functions */
1680 /* ========================================================================= */
1682 void OpenAudio(void)
1684 /* always start with reliable default values */
1685 audio.sound_available = FALSE;
1686 audio.music_available = FALSE;
1687 audio.loops_available = FALSE;
1689 audio.sound_enabled = FALSE;
1690 audio.sound_deactivated = FALSE;
1692 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1693 audio.mixer_pid = 0;
1694 audio.device_name = NULL;
1695 audio.device_fd = -1;
1697 audio.num_channels = 0;
1698 audio.music_channel = 0;
1699 audio.first_sound_channel = 0;
1701 #if defined(TARGET_SDL)
1706 void CloseAudio(void)
1708 #if defined(TARGET_SDL)
1712 audio.sound_enabled = FALSE;
1715 void SetAudioMode(boolean enabled)
1717 if (!audio.sound_available)
1720 audio.sound_enabled = enabled;
1724 /* ========================================================================= */
1725 /* event functions */
1726 /* ========================================================================= */
1728 void InitEventFilter(EventFilter filter_function)
1730 /* set event filter to filter out certain events */
1731 #if defined(TARGET_SDL)
1732 #if defined(TARGET_SDL2)
1733 SDL_SetEventFilter(filter_function, NULL);
1735 SDL_SetEventFilter(filter_function);
1740 boolean PendingEvent(void)
1742 #if defined(TARGET_SDL)
1743 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1745 return (XPending(display) ? TRUE : FALSE);
1749 void NextEvent(Event *event)
1751 #if defined(TARGET_SDL)
1752 SDLNextEvent(event);
1754 XNextEvent(display, event);
1758 void PeekEvent(Event *event)
1760 #if defined(TARGET_SDL)
1761 #if defined(TARGET_SDL2)
1762 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1764 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1767 XPeekEvent(display, event);
1771 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1773 #if defined(TARGET_SDL)
1774 #if defined(TARGET_SDL2)
1775 /* key up/down events in SDL2 do not return text characters anymore */
1776 return event->keysym.sym;
1780 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1781 (int)event->keysym.unicode,
1782 (int)event->keysym.sym,
1783 (int)SDL_GetModState());
1786 if (with_modifiers &&
1787 event->keysym.unicode > 0x0000 &&
1788 event->keysym.unicode < 0x2000)
1789 return event->keysym.unicode;
1791 return event->keysym.sym;
1797 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1798 (int)XLookupKeysym(event, event->state),
1799 (int)XLookupKeysym(event, 0));
1803 return XLookupKeysym(event, event->state);
1805 return XLookupKeysym(event, 0);
1809 KeyMod HandleKeyModState(Key key, int key_status)
1811 static KeyMod current_modifiers = KMOD_None;
1813 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1815 KeyMod new_modifier = KMOD_None;
1820 new_modifier = KMOD_Shift_L;
1823 new_modifier = KMOD_Shift_R;
1825 case KSYM_Control_L:
1826 new_modifier = KMOD_Control_L;
1828 case KSYM_Control_R:
1829 new_modifier = KMOD_Control_R;
1832 new_modifier = KMOD_Meta_L;
1835 new_modifier = KMOD_Meta_R;
1838 new_modifier = KMOD_Alt_L;
1841 new_modifier = KMOD_Alt_R;
1847 if (key_status == KEY_PRESSED)
1848 current_modifiers |= new_modifier;
1850 current_modifiers &= ~new_modifier;
1853 return current_modifiers;
1856 KeyMod GetKeyModState()
1858 #if defined(TARGET_SDL)
1859 return (KeyMod)SDL_GetModState();
1861 return HandleKeyModState(KSYM_UNDEFINED, 0);
1865 KeyMod GetKeyModStateFromEvents()
1867 /* always use key modifier state as tracked from key events (this is needed
1868 if the modifier key event was injected into the event queue, but the key
1869 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1870 query the keys as held pressed on the keyboard) -- this case is currently
1871 only used to filter out clipboard insert events from "True X-Mouse" tool */
1873 return HandleKeyModState(KSYM_UNDEFINED, 0);
1876 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1878 if (event->type != EVENT_CLIENTMESSAGE)
1881 #if defined(TARGET_SDL)
1882 return TRUE; /* the only possible message here is SDL_QUIT */
1889 /* ========================================================================= */
1890 /* joystick functions */
1891 /* ========================================================================= */
1893 void InitJoysticks()
1897 #if defined(NO_JOYSTICK)
1898 return; /* joysticks generally deactivated by compile-time directive */
1901 /* always start with reliable default values */
1902 joystick.status = JOYSTICK_NOT_AVAILABLE;
1903 for (i = 0; i < MAX_PLAYERS; i++)
1904 joystick.fd[i] = -1; /* joystick device closed */
1906 #if defined(TARGET_SDL)
1911 for (i = 0; i < MAX_PLAYERS; i++)
1912 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1916 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1918 #if defined(TARGET_SDL)
1919 return SDLReadJoystick(nr, x, y, b1, b2);