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)
1118 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1120 SDLZoomBitmap(src_bitmap, dst_bitmap);
1125 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1126 int tile_size, boolean create_small_bitmaps)
1130 Bitmap *tmp_bitmap_final = NULL;
1131 Bitmap *tmp_bitmap_0 = NULL;
1132 Bitmap *tmp_bitmap_1 = NULL;
1133 Bitmap *tmp_bitmap_2 = NULL;
1134 Bitmap *tmp_bitmap_4 = NULL;
1135 Bitmap *tmp_bitmap_8 = NULL;
1136 Bitmap *tmp_bitmap_16 = NULL;
1137 Bitmap *tmp_bitmap_32 = NULL;
1138 int width_final, height_final;
1139 int width_0, height_0;
1140 int width_1, height_1;
1141 int width_2, height_2;
1142 int width_4, height_4;
1143 int width_8, height_8;
1144 int width_16, height_16;
1146 int width_32, height_32;
1148 int old_width, old_height;
1149 int new_width, new_height;
1151 old_width = old_bitmap->width;
1152 old_height = old_bitmap->height;
1155 /* calculate new image dimensions for final image size */
1156 width_final = old_width * zoom_factor;
1157 height_final = old_height * zoom_factor;
1159 /* get image with final size (this might require scaling up) */
1160 /* ("final" size may result in non-standard tile size image) */
1161 if (zoom_factor != 1)
1162 tmp_bitmap_final = ZoomBitmap(old_bitmap, width_final, height_final);
1164 tmp_bitmap_final = old_bitmap;
1168 /* calculate new image dimensions for final image size */
1169 width_1 = old_width * zoom_factor;
1170 height_1 = old_height * zoom_factor;
1172 /* get image with final size (this might require scaling up) */
1173 /* ("final" size may result in non-standard tile size image) */
1174 if (zoom_factor != 1)
1175 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1177 tmp_bitmap_1 = old_bitmap;
1180 UPDATE_BUSY_STATE();
1182 width_0 = width_1 = width_final;
1183 height_0 = height_1 = height_final;
1185 tmp_bitmap_0 = tmp_bitmap_1 = tmp_bitmap_final;
1188 if (create_small_bitmaps)
1190 /* check if we have a non-gameplay tile size image */
1191 if (tile_size != gfx.game_tile_size)
1193 /* get image with gameplay tile size */
1194 width_0 = width_final * gfx.game_tile_size / tile_size;
1195 height_0 = height_final * gfx.game_tile_size / tile_size;
1197 if (width_0 == old_width)
1198 tmp_bitmap_0 = old_bitmap;
1199 else if (width_0 == width_final)
1200 tmp_bitmap_0 = tmp_bitmap_final;
1202 tmp_bitmap_0 = ZoomBitmap(old_bitmap, width_0, height_0);
1204 UPDATE_BUSY_STATE();
1207 /* check if we have a non-standard tile size image */
1208 if (tile_size != gfx.standard_tile_size)
1210 /* get image with standard tile size */
1211 width_1 = width_final * gfx.standard_tile_size / tile_size;
1212 height_1 = height_final * gfx.standard_tile_size / tile_size;
1214 if (width_1 == old_width)
1215 tmp_bitmap_1 = old_bitmap;
1216 else if (width_1 == width_final)
1217 tmp_bitmap_1 = tmp_bitmap_final;
1218 else if (width_1 == width_0)
1219 tmp_bitmap_1 = tmp_bitmap_0;
1221 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1223 UPDATE_BUSY_STATE();
1228 if (create_small_bitmaps)
1230 /* calculate new image dimensions for small images */
1231 width_2 = width_1 / 2;
1232 height_2 = height_1 / 2;
1233 width_4 = width_1 / 4;
1234 height_4 = height_1 / 4;
1235 width_8 = width_1 / 8;
1236 height_8 = height_1 / 8;
1237 width_16 = width_1 / 16;
1238 height_16 = height_1 / 16;
1240 width_32 = width_1 / 32;
1241 height_32 = height_1 / 32;
1245 /* get image with 1/2 of normal size (for use in the level editor) */
1246 if (width_2 == old_width)
1247 tmp_bitmap_2 = old_bitmap;
1249 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_2, height_2);
1251 UPDATE_BUSY_STATE();
1253 /* get image with 1/4 of normal size (for use in the level editor) */
1254 if (width_4 == old_width)
1255 tmp_bitmap_4 = old_bitmap;
1257 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_4, height_4);
1259 UPDATE_BUSY_STATE();
1261 /* get image with 1/8 of normal size (for use on the preview screen) */
1262 if (width_8 == old_width)
1263 tmp_bitmap_8 = old_bitmap;
1265 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_8, height_8);
1267 UPDATE_BUSY_STATE();
1269 /* get image with 1/16 of normal size (for use on the preview screen) */
1270 if (width_16 == old_width)
1271 tmp_bitmap_16 = old_bitmap;
1273 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_16, height_16);
1275 UPDATE_BUSY_STATE();
1277 /* get image with 1/32 of normal size (for use on the preview screen) */
1278 if (width_32 == old_width)
1279 tmp_bitmap_32 = old_bitmap;
1281 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_32, height_32);
1283 UPDATE_BUSY_STATE();
1287 /* get image with 1/2 of normal size (for use in the level editor) */
1288 if (zoom_factor != 2)
1289 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1291 tmp_bitmap_2 = old_bitmap;
1293 UPDATE_BUSY_STATE();
1295 /* get image with 1/4 of normal size (for use in the level editor) */
1296 if (zoom_factor != 4)
1297 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1299 tmp_bitmap_4 = old_bitmap;
1301 UPDATE_BUSY_STATE();
1303 /* get image with 1/8 of normal size (for use on the preview screen) */
1304 if (zoom_factor != 8)
1305 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1307 tmp_bitmap_8 = old_bitmap;
1309 UPDATE_BUSY_STATE();
1311 /* get image with 1/16 of normal size (for use on the preview screen) */
1312 if (zoom_factor != 16)
1313 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1315 tmp_bitmap_16 = old_bitmap;
1317 UPDATE_BUSY_STATE();
1319 /* get image with 1/32 of normal size (for use on the preview screen) */
1320 if (zoom_factor != 32)
1321 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1323 tmp_bitmap_32 = old_bitmap;
1325 UPDATE_BUSY_STATE();
1330 /* if image was scaled up, create new clipmask for normal size image */
1331 if (zoom_factor != 1)
1333 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1335 if (old_bitmap->surface_masked)
1336 SDL_FreeSurface(old_bitmap->surface_masked);
1338 SDL_SetColorKey(tmp_surface_1, SET_TRANSPARENT_PIXEL,
1339 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1340 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1341 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1342 SDL_SetColorKey(tmp_surface_1, UNSET_TRANSPARENT_PIXEL, 0);
1346 if (create_small_bitmaps)
1348 new_width = width_1;
1349 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1352 if (width_0 != width_1)
1354 new_width += width_0;
1355 new_height = MAX(new_height, height_0);
1359 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1362 if (width_0 != width_1)
1363 BlitBitmap(tmp_bitmap_0, new_bitmap, 0, 0, width_0, height_0, width_1, 0);
1366 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1367 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1369 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1370 width_1 / 2, height_1);
1371 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1372 3 * width_1 / 4, height_1);
1373 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1374 7 * width_1 / 8, height_1);
1375 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1376 15 * width_1 / 16, height_1);
1378 UPDATE_BUSY_STATE();
1382 new_width = width_1;
1383 new_height = height_1;
1385 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1388 if (create_small_bitmaps)
1390 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1393 if (tmp_bitmap_final != old_bitmap)
1394 FreeBitmap(tmp_bitmap_final);
1396 if (tmp_bitmap_0 != old_bitmap &&
1397 tmp_bitmap_0 != tmp_bitmap_final)
1398 FreeBitmap(tmp_bitmap_0);
1400 if (tmp_bitmap_1 != old_bitmap &&
1401 tmp_bitmap_1 != tmp_bitmap_final &&
1402 tmp_bitmap_1 != tmp_bitmap_0)
1403 FreeBitmap(tmp_bitmap_1);
1405 if (tmp_bitmap_2 != old_bitmap)
1406 FreeBitmap(tmp_bitmap_2);
1408 if (tmp_bitmap_4 != old_bitmap)
1409 FreeBitmap(tmp_bitmap_4);
1411 if (tmp_bitmap_8 != old_bitmap)
1412 FreeBitmap(tmp_bitmap_8);
1414 if (tmp_bitmap_16 != old_bitmap)
1415 FreeBitmap(tmp_bitmap_16);
1417 if (tmp_bitmap_32 != old_bitmap)
1418 FreeBitmap(tmp_bitmap_32);
1422 if (zoom_factor != 1)
1423 FreeBitmap(tmp_bitmap_1);
1425 if (zoom_factor != 2)
1426 FreeBitmap(tmp_bitmap_2);
1428 if (zoom_factor != 4)
1429 FreeBitmap(tmp_bitmap_4);
1431 if (zoom_factor != 8)
1432 FreeBitmap(tmp_bitmap_8);
1434 if (zoom_factor != 16)
1435 FreeBitmap(tmp_bitmap_16);
1437 if (zoom_factor != 32)
1438 FreeBitmap(tmp_bitmap_32);
1442 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1443 #if defined(TARGET_SDL)
1444 swap_bitmap.surface = old_bitmap->surface;
1445 old_bitmap->surface = new_bitmap->surface;
1446 new_bitmap->surface = swap_bitmap.surface;
1448 swap_bitmap.drawable = old_bitmap->drawable;
1449 old_bitmap->drawable = new_bitmap->drawable;
1450 new_bitmap->drawable = swap_bitmap.drawable;
1453 old_bitmap->width = new_bitmap->width;
1454 old_bitmap->height = new_bitmap->height;
1457 /* this replaces all blit masks created when loading -- maybe optimize this */
1459 SDL_Surface *old_surface = old_bitmap->surface;
1461 if (old_bitmap->surface_masked)
1462 SDL_FreeSurface(old_bitmap->surface_masked);
1464 SDL_SetColorKey(old_surface, SET_TRANSPARENT_PIXEL,
1465 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1467 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) == NULL)
1468 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1470 SDL_SetColorKey(old_surface, UNSET_TRANSPARENT_PIXEL, 0);
1474 UPDATE_BUSY_STATE();
1476 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1479 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor,
1482 CreateScaledBitmaps(old_bitmap, zoom_factor, tile_size, TRUE);
1485 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1487 CreateScaledBitmaps(old_bitmap, zoom_factor, 0, FALSE);
1491 /* ------------------------------------------------------------------------- */
1492 /* mouse pointer functions */
1493 /* ------------------------------------------------------------------------- */
1495 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1497 /* XPM image definitions */
1498 static const char *cursor_image_none[] =
1500 /* width height num_colors chars_per_pixel */
1530 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1531 static const char *cursor_image_dot[] =
1533 /* width height num_colors chars_per_pixel */
1562 static const char **cursor_image_playfield = cursor_image_dot;
1564 /* some people complained about a "white dot" on the screen and thought it
1565 was a graphical error... OK, let's just remove the whole pointer :-) */
1566 static const char **cursor_image_playfield = cursor_image_none;
1569 static const int cursor_bit_order = BIT_ORDER_MSB;
1571 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1573 struct MouseCursorInfo *cursor;
1574 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1575 int header_lines = 4;
1578 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1580 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1583 for (y = 0; y < cursor->width; y++)
1585 for (x = 0; x < cursor->height; x++)
1588 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1593 cursor->data[i] = cursor->mask[i] = 0;
1596 switch (image[header_lines + y][x])
1599 cursor->data[i] |= bit_mask;
1600 cursor->mask[i] |= bit_mask;
1604 cursor->mask[i] |= bit_mask;
1613 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1618 void SetMouseCursor(int mode)
1620 static struct MouseCursorInfo *cursor_none = NULL;
1621 static struct MouseCursorInfo *cursor_playfield = NULL;
1622 struct MouseCursorInfo *cursor_new;
1624 if (cursor_none == NULL)
1625 cursor_none = get_cursor_from_image(cursor_image_none);
1627 if (cursor_playfield == NULL)
1628 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1630 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1631 mode == CURSOR_NONE ? cursor_none :
1632 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1634 SDLSetMouseCursor(cursor_new);
1638 /* ========================================================================= */
1639 /* audio functions */
1640 /* ========================================================================= */
1642 void OpenAudio(void)
1644 /* always start with reliable default values */
1645 audio.sound_available = FALSE;
1646 audio.music_available = FALSE;
1647 audio.loops_available = FALSE;
1649 audio.sound_enabled = FALSE;
1650 audio.sound_deactivated = FALSE;
1652 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1653 audio.mixer_pid = 0;
1654 audio.device_name = NULL;
1655 audio.device_fd = -1;
1657 audio.num_channels = 0;
1658 audio.music_channel = 0;
1659 audio.first_sound_channel = 0;
1661 #if defined(TARGET_SDL)
1666 void CloseAudio(void)
1668 #if defined(TARGET_SDL)
1672 audio.sound_enabled = FALSE;
1675 void SetAudioMode(boolean enabled)
1677 if (!audio.sound_available)
1680 audio.sound_enabled = enabled;
1684 /* ========================================================================= */
1685 /* event functions */
1686 /* ========================================================================= */
1688 void InitEventFilter(EventFilter filter_function)
1690 /* set event filter to filter out certain events */
1691 #if defined(TARGET_SDL)
1692 #if defined(TARGET_SDL2)
1693 SDL_SetEventFilter(filter_function, NULL);
1695 SDL_SetEventFilter(filter_function);
1700 boolean PendingEvent(void)
1702 #if defined(TARGET_SDL)
1703 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1705 return (XPending(display) ? TRUE : FALSE);
1709 void NextEvent(Event *event)
1711 #if defined(TARGET_SDL)
1712 SDLNextEvent(event);
1714 XNextEvent(display, event);
1718 void PeekEvent(Event *event)
1720 #if defined(TARGET_SDL)
1721 #if defined(TARGET_SDL2)
1722 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
1724 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1727 XPeekEvent(display, event);
1731 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1733 #if defined(TARGET_SDL)
1734 #if defined(TARGET_SDL2)
1735 /* key up/down events in SDL2 do not return text characters anymore */
1736 return event->keysym.sym;
1740 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1741 (int)event->keysym.unicode,
1742 (int)event->keysym.sym,
1743 (int)SDL_GetModState());
1746 if (with_modifiers &&
1747 event->keysym.unicode > 0x0000 &&
1748 event->keysym.unicode < 0x2000)
1749 return event->keysym.unicode;
1751 return event->keysym.sym;
1757 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1758 (int)XLookupKeysym(event, event->state),
1759 (int)XLookupKeysym(event, 0));
1763 return XLookupKeysym(event, event->state);
1765 return XLookupKeysym(event, 0);
1769 KeyMod HandleKeyModState(Key key, int key_status)
1771 static KeyMod current_modifiers = KMOD_None;
1773 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1775 KeyMod new_modifier = KMOD_None;
1780 new_modifier = KMOD_Shift_L;
1783 new_modifier = KMOD_Shift_R;
1785 case KSYM_Control_L:
1786 new_modifier = KMOD_Control_L;
1788 case KSYM_Control_R:
1789 new_modifier = KMOD_Control_R;
1792 new_modifier = KMOD_Meta_L;
1795 new_modifier = KMOD_Meta_R;
1798 new_modifier = KMOD_Alt_L;
1801 new_modifier = KMOD_Alt_R;
1807 if (key_status == KEY_PRESSED)
1808 current_modifiers |= new_modifier;
1810 current_modifiers &= ~new_modifier;
1813 return current_modifiers;
1816 KeyMod GetKeyModState()
1818 #if defined(TARGET_SDL)
1819 return (KeyMod)SDL_GetModState();
1821 return HandleKeyModState(KSYM_UNDEFINED, 0);
1825 KeyMod GetKeyModStateFromEvents()
1827 /* always use key modifier state as tracked from key events (this is needed
1828 if the modifier key event was injected into the event queue, but the key
1829 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1830 query the keys as held pressed on the keyboard) -- this case is currently
1831 only used to filter out clipboard insert events from "True X-Mouse" tool */
1833 return HandleKeyModState(KSYM_UNDEFINED, 0);
1836 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1838 if (event->type != EVENT_CLIENTMESSAGE)
1841 #if defined(TARGET_SDL)
1842 return TRUE; /* the only possible message here is SDL_QUIT */
1849 /* ========================================================================= */
1850 /* joystick functions */
1851 /* ========================================================================= */
1853 void InitJoysticks()
1857 #if defined(NO_JOYSTICK)
1858 return; /* joysticks generally deactivated by compile-time directive */
1861 /* always start with reliable default values */
1862 joystick.status = JOYSTICK_NOT_AVAILABLE;
1863 for (i = 0; i < MAX_PLAYERS; i++)
1864 joystick.fd[i] = -1; /* joystick device closed */
1866 #if defined(TARGET_SDL)
1871 for (i = 0; i < MAX_PLAYERS; i++)
1872 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1876 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1878 #if defined(TARGET_SDL)
1879 return SDLReadJoystick(nr, x, y, b1, b2);