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 ***********************************************************/
19 #if defined(PLATFORM_MSDOS)
31 /* ========================================================================= */
32 /* exported variables */
33 /* ========================================================================= */
35 struct ProgramInfo program;
36 struct OptionInfo options;
37 struct VideoSystemInfo video;
38 struct AudioSystemInfo audio;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
44 LevelDirTree *leveldir_first_all = NULL;
45 LevelDirTree *leveldir_first = NULL;
46 LevelDirTree *leveldir_current = NULL;
49 Display *display = NULL;
50 Visual *visual = NULL;
54 DrawWindow *window = NULL;
55 DrawBuffer *backbuffer = NULL;
56 DrawBuffer *drawto = NULL;
58 int button_status = MB_NOT_PRESSED;
59 boolean motion_status = FALSE;
61 int redraw_mask = REDRAW_NONE;
67 /* ========================================================================= */
68 /* init/close functions */
69 /* ========================================================================= */
71 void InitProgramInfo(char *argv0,
72 char *userdata_subdir, char *userdata_subdir_unix,
73 char *program_title, char *window_title, char *icon_title,
74 char *x11_icon_filename, char *x11_iconmask_filename,
75 char *sdl_icon_filename, char *msdos_cursor_filename,
76 char *cookie_prefix, char *filename_prefix,
79 program.command_basepath = getBasePath(argv0);
80 program.command_basename = getBaseName(argv0);
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_subdir_unix = userdata_subdir_unix;
84 program.userdata_path = getUserGameDataDir();
86 program.program_title = program_title;
87 program.window_title = window_title;
88 program.icon_title = icon_title;
90 program.x11_icon_filename = x11_icon_filename;
91 program.x11_iconmask_filename = x11_iconmask_filename;
92 program.sdl_icon_filename = sdl_icon_filename;
93 program.msdos_cursor_filename = msdos_cursor_filename;
95 program.cookie_prefix = cookie_prefix;
96 program.filename_prefix = filename_prefix;
98 program.version_major = VERSION_MAJOR(program_version);
99 program.version_minor = VERSION_MINOR(program_version);
100 program.version_patch = VERSION_PATCH(program_version);
102 program.error_filename = getErrorFilename(ERROR_BASENAME);
103 program.error_file = stderr;
106 void InitExitFunction(void (*exit_function)(int))
108 program.exit_function = exit_function;
110 /* set signal handlers to custom exit function */
111 signal(SIGINT, exit_function);
112 signal(SIGTERM, exit_function);
114 #if defined(TARGET_SDL)
115 /* set exit function to automatically cleanup SDL stuff after exit() */
120 void InitPlatformDependentStuff(void)
122 #if defined(PLATFORM_MSDOS)
126 #if defined(PLATFORM_MACOSX)
127 updateUserGameDataDir();
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
134 #if defined(TARGET_SDL)
135 if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
142 void ClosePlatformDependentStuff(void)
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
148 #if defined(PLATFORM_MSDOS)
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154 int real_sx, int real_sy,
155 int full_sxsize, int full_sysize,
156 Bitmap *field_save_buffer)
162 gfx.real_sx = real_sx;
163 gfx.real_sy = real_sy;
164 gfx.full_sxsize = full_sxsize;
165 gfx.full_sysize = full_sysize;
167 gfx.field_save_buffer = field_save_buffer;
170 gfx.background_bitmap = NULL;
171 gfx.background_bitmap_mask = REDRAW_NONE;
174 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
175 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
196 gfx.win_xsize = win_xsize;
197 gfx.win_ysize = win_ysize;
200 gfx.background_bitmap_mask = REDRAW_NONE;
202 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
208 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210 gfx.scrollbuffer_width = scrollbuffer_width;
211 gfx.scrollbuffer_height = scrollbuffer_height;
214 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
216 gfx.draw_busy_anim_function = draw_busy_anim_function;
219 void InitGfxCustomArtworkInfo()
221 gfx.override_level_graphics = FALSE;
222 gfx.override_level_sounds = FALSE;
223 gfx.override_level_music = FALSE;
225 gfx.draw_init_text = TRUE;
228 void SetDrawDeactivationMask(int draw_deactivation_mask)
230 gfx.draw_deactivation_mask = draw_deactivation_mask;
233 void SetDrawBackgroundMask(int draw_background_mask)
235 gfx.draw_background_mask = draw_background_mask;
238 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
239 int dest_x, int dest_y, int width, int height)
241 int bitmap_xsize = width;
242 int bitmap_ysize = height;
243 int tile_xsize = tile->width;
244 int tile_ysize = tile->height;
245 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
246 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
249 for (y = 0; y < tile_ysteps; y++)
251 for (x = 0; x < tile_xsteps; x++)
253 int draw_x = dest_x + x * tile_xsize;
254 int draw_y = dest_y + y * tile_ysize;
255 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
256 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
258 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
263 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
265 if (background_bitmap_tile != NULL)
266 gfx.background_bitmap_mask |= mask;
268 gfx.background_bitmap_mask &= ~mask;
271 if (gfx.background_bitmap == NULL)
272 gfx.background_bitmap = CreateBitmap(video.width, video.height,
276 if (background_bitmap_tile == NULL) /* empty background requested */
279 if (mask == REDRAW_ALL)
280 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
281 0, 0, video.width, video.height);
282 else if (mask == REDRAW_FIELD)
283 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
284 gfx.real_sx, gfx.real_sy,
285 gfx.full_sxsize, gfx.full_sysize);
286 else if (mask == REDRAW_DOOR_1)
288 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
290 gfx.dxsize, gfx.dysize);
294 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
296 /* remove every mask before setting mask for window */
297 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
298 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
299 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
302 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
304 /* remove window area mask before setting mask for main area */
305 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
306 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
307 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
310 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
312 /* remove window area mask before setting mask for door area */
313 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
314 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
315 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
319 /* ========================================================================= */
320 /* video functions */
321 /* ========================================================================= */
323 inline static int GetRealDepth(int depth)
325 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
328 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
329 int width, int height, Pixel color)
331 #if defined(TARGET_SDL)
332 SDLFillRectangle(bitmap, x, y, width, height, color);
334 X11FillRectangle(bitmap, x, y, width, height, color);
338 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
339 int src_x, int src_y, int width, int height,
340 int dst_x, int dst_y, int mask_mode)
342 #if defined(TARGET_SDL)
343 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
344 dst_x, dst_y, mask_mode);
346 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
347 dst_x, dst_y, mask_mode);
351 void InitVideoDisplay(void)
353 #if defined(TARGET_SDL)
354 SDLInitVideoDisplay();
356 X11InitVideoDisplay();
360 void CloseVideoDisplay(void)
362 KeyboardAutoRepeatOn();
364 #if defined(TARGET_SDL)
365 SDL_QuitSubSystem(SDL_INIT_VIDEO);
368 XCloseDisplay(display);
372 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
375 video.height = height;
376 video.depth = GetRealDepth(depth);
378 video.fullscreen_available = FULLSCREEN_STATUS;
379 video.fullscreen_enabled = FALSE;
381 video.fullscreen_mode_current = NULL;
382 video.fullscreen_modes = NULL;
385 #if defined(TARGET_SDL)
386 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
388 X11InitVideoBuffer(&backbuffer, &window);
394 inline static void FreeBitmapPointers(Bitmap *bitmap)
399 #if defined(TARGET_SDL)
400 SDLFreeBitmapPointers(bitmap);
402 X11FreeBitmapPointers(bitmap);
405 checked_free(bitmap->source_filename);
406 bitmap->source_filename = NULL;
409 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
412 if (src_bitmap == NULL || dst_bitmap == NULL)
415 FreeBitmapPointers(dst_bitmap);
417 *dst_bitmap = *src_bitmap;
420 void FreeBitmap(Bitmap *bitmap)
425 FreeBitmapPointers(bitmap);
430 Bitmap *CreateBitmapStruct(void)
432 #if defined(TARGET_SDL)
433 return checked_calloc(sizeof(struct SDLSurfaceInfo));
435 return checked_calloc(sizeof(struct X11DrawableInfo));
439 Bitmap *CreateBitmap(int width, int height, int depth)
441 Bitmap *new_bitmap = CreateBitmapStruct();
442 int real_width = MAX(1, width); /* prevent zero bitmap width */
443 int real_height = MAX(1, height); /* prevent zero bitmap height */
444 int real_depth = GetRealDepth(depth);
446 #if defined(TARGET_SDL)
447 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
449 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
452 new_bitmap->width = real_width;
453 new_bitmap->height = real_height;
458 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
460 Bitmap *new_bitmap = CreateBitmap(width, height, depth);
464 *bitmap = new_bitmap;
468 TransferBitmapPointers(new_bitmap, *bitmap);
473 void CloseWindow(DrawWindow *window)
475 #if defined(TARGET_X11)
476 X11CloseWindow(window);
480 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
483 if (draw_mask == REDRAW_NONE)
486 if (draw_mask & REDRAW_ALL)
489 if ((draw_mask & REDRAW_FIELD) &&
490 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
493 if ((draw_mask & REDRAW_DOOR_1) &&
494 x >= gfx.dx && y < gfx.dy + gfx.dysize)
497 if ((draw_mask & REDRAW_DOOR_2) &&
498 x >= gfx.dx && y >= gfx.vy)
504 boolean DrawingDeactivated(int x, int y, int width, int height)
506 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
509 boolean DrawingOnBackground(int x, int y)
511 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
512 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
515 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
516 int src_x, int src_y, int width, int height,
517 int dst_x, int dst_y)
519 if (DrawingDeactivated(dst_x, dst_y, width, height))
523 /* skip if rectangle starts outside bitmap */
524 if (src_x >= src_bitmap->width ||
525 src_y >= src_bitmap->height ||
526 dst_x >= dst_bitmap->width ||
527 dst_y >= dst_bitmap->height)
530 /* clip if rectangle overlaps bitmap */
531 if (src_x + width > src_bitmap->width)
532 width = src_bitmap->width - src_x;
533 if (src_y + height > src_bitmap->height)
534 height = src_bitmap->height - src_y;
535 if (dst_x + width > dst_bitmap->width)
536 width = dst_bitmap->width - dst_x;
537 if (dst_y + height > dst_bitmap->height)
538 height = dst_bitmap->height - dst_y;
542 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
543 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
544 but is already fixed in SVN and should therefore finally be fixed with
545 the next official SDL release, which is probably version 1.2.14.) */
547 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
548 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
549 if (src_bitmap == dst_bitmap)
551 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
553 /* needed when blitting directly to same bitmap -- should not be needed with
554 recent SDL libraries, but apparently does not work in 1.2.11 directly */
556 static Bitmap *tmp_bitmap = NULL;
557 static int tmp_bitmap_xsize = 0;
558 static int tmp_bitmap_ysize = 0;
560 /* start with largest static bitmaps for initial bitmap size ... */
561 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
563 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
564 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
567 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
568 if (src_bitmap->width > tmp_bitmap_xsize ||
569 src_bitmap->height > tmp_bitmap_ysize)
571 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
572 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
574 FreeBitmap(tmp_bitmap);
579 if (tmp_bitmap == NULL)
580 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
583 sysCopyArea(src_bitmap, tmp_bitmap,
584 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
585 sysCopyArea(tmp_bitmap, dst_bitmap,
586 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
594 sysCopyArea(src_bitmap, dst_bitmap,
595 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
598 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
599 int fade_mode, int fade_delay, int post_delay,
600 void (*draw_border_function)(void))
602 #if defined(TARGET_SDL)
603 SDLFadeRectangle(bitmap_cross, x, y, width, height,
604 fade_mode, fade_delay, post_delay, draw_border_function);
606 X11FadeRectangle(bitmap_cross, x, y, width, height,
607 fade_mode, fade_delay, post_delay, draw_border_function);
611 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
614 if (DrawingDeactivated(x, y, width, height))
618 /* skip if rectangle starts outside bitmap */
619 if (x >= bitmap->width ||
623 /* clip if rectangle overlaps bitmap */
624 if (x + width > bitmap->width)
625 width = bitmap->width - x;
626 if (y + height > bitmap->height)
627 height = bitmap->height - y;
630 sysFillRectangle(bitmap, x, y, width, height, color);
633 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
635 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
638 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
639 int width, int height)
641 if (DrawingOnBackground(x, y))
642 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
644 ClearRectangle(bitmap, x, y, width, height);
647 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
649 #if defined(TARGET_X11)
652 bitmap->clip_gc = clip_gc;
653 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
658 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
660 #if defined(TARGET_X11)
663 bitmap->clip_gc = clip_gc;
664 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
669 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
670 int src_x, int src_y, int width, int height,
671 int dst_x, int dst_y)
673 if (DrawingDeactivated(dst_x, dst_y, width, height))
676 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
677 dst_x, dst_y, BLIT_MASKED);
680 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
681 int src_x, int src_y, int width, int height,
682 int dst_x, int dst_y)
684 if (DrawingOnBackground(dst_x, dst_y))
686 /* draw background */
687 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
690 /* draw foreground */
691 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
692 dst_x - src_x, dst_y - src_y);
693 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
697 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
701 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
704 #if defined(TARGET_SDL)
705 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
707 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
711 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
714 #if defined(TARGET_SDL)
715 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
717 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
721 #if !defined(TARGET_X11_NATIVE)
722 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
723 int to_x, int to_y, Pixel pixel, int line_width)
727 for (x = 0; x < line_width; x++)
729 for (y = 0; y < line_width; y++)
731 int dx = x - line_width / 2;
732 int dy = y - line_width / 2;
734 if ((x == 0 && y == 0) ||
735 (x == 0 && y == line_width - 1) ||
736 (x == line_width - 1 && y == 0) ||
737 (x == line_width - 1 && y == line_width - 1))
740 #if defined(TARGET_SDL)
742 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
743 #elif defined(TARGET_ALLEGRO)
744 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
745 to_x + dx, to_y + dy, pixel);
752 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
754 #if !defined(TARGET_X11_NATIVE)
758 for (i = 0; i < num_points - 1; i++)
759 DrawLine(bitmap, points[i].x, points[i].y,
760 points[i + 1].x, points[i + 1].y, pixel, line_width);
763 SDLDrawLines(bitmap->surface, points, num_points, pixel);
766 XSetForeground(display, bitmap->line_gc[1], pixel);
767 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
768 (XPoint *)points, num_points, CoordModeOrigin);
772 Pixel GetPixel(Bitmap *bitmap, int x, int y)
774 if (x < 0 || x >= bitmap->width ||
775 y < 0 || y >= bitmap->height)
778 #if defined(TARGET_SDL)
779 return SDLGetPixel(bitmap, x, y);
780 #elif defined(TARGET_ALLEGRO)
781 return AllegroGetPixel(bitmap->drawable, x, y);
783 return X11GetPixel(bitmap, x, y);
787 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
788 unsigned int color_g, unsigned int color_b)
790 #if defined(TARGET_SDL)
791 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
792 #elif defined(TARGET_ALLEGRO)
793 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
795 return X11GetPixelFromRGB(color_r, color_g, color_b);
799 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
801 unsigned int color_r = (color >> 16) & 0xff;
802 unsigned int color_g = (color >> 8) & 0xff;
803 unsigned int color_b = (color >> 0) & 0xff;
805 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
808 /* execute all pending screen drawing operations */
809 void FlushDisplay(void)
816 /* execute and wait for all pending screen drawing operations */
817 void SyncDisplay(void)
820 XSync(display, FALSE);
824 void KeyboardAutoRepeatOn(void)
826 #if defined(TARGET_SDL)
827 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
828 SDL_DEFAULT_REPEAT_INTERVAL / 2);
829 SDL_EnableUNICODE(1);
832 XAutoRepeatOn(display);
836 void KeyboardAutoRepeatOff(void)
838 #if defined(TARGET_SDL)
839 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
840 SDL_EnableUNICODE(0);
843 XAutoRepeatOff(display);
847 boolean PointerInWindow(DrawWindow *window)
849 #if defined(TARGET_SDL)
857 /* if XQueryPointer() returns False, the pointer
858 is not on the same screen as the specified window */
859 return XQueryPointer(display, window->drawable, &root, &child,
860 &root_x, &root_y, &win_x, &win_y, &mask);
864 boolean SetVideoMode(boolean fullscreen)
866 #if defined(TARGET_SDL)
867 return SDLSetVideoMode(&backbuffer, fullscreen);
869 boolean success = TRUE;
871 if (fullscreen && video.fullscreen_available)
873 Error(ERR_WARN, "fullscreen not available in X11 version");
875 /* display error message only once */
876 video.fullscreen_available = FALSE;
885 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
887 #if defined(TARGET_SDL)
888 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
889 (!fullscreen && video.fullscreen_enabled))
890 fullscreen = SetVideoMode(fullscreen);
896 Bitmap *LoadImage(char *filename)
900 #if defined(TARGET_SDL)
901 new_bitmap = SDLLoadImage(filename);
903 new_bitmap = X11LoadImage(filename);
907 new_bitmap->source_filename = getStringCopy(filename);
912 Bitmap *LoadCustomImage(char *basename)
914 char *filename = getCustomImageFilename(basename);
917 if (filename == NULL)
918 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
920 if ((new_bitmap = LoadImage(filename)) == NULL)
921 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
926 void ReloadCustomImage(Bitmap *bitmap, char *basename)
928 char *filename = getCustomImageFilename(basename);
931 if (filename == NULL) /* (should never happen) */
933 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
937 if (strEqual(filename, bitmap->source_filename))
939 /* The old and new image are the same (have the same filename and path).
940 This usually means that this image does not exist in this graphic set
941 and a fallback to the existing image is done. */
946 if ((new_bitmap = LoadImage(filename)) == NULL)
948 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
952 if (bitmap->width != new_bitmap->width ||
953 bitmap->height != new_bitmap->height)
955 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
957 FreeBitmap(new_bitmap);
961 TransferBitmapPointers(new_bitmap, bitmap);
965 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
967 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
969 #if defined(TARGET_SDL)
970 SDLZoomBitmap(src_bitmap, dst_bitmap);
972 X11ZoomBitmap(src_bitmap, dst_bitmap);
978 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
979 boolean create_small_bitmaps)
983 Bitmap *tmp_bitmap_1;
984 Bitmap *tmp_bitmap_2;
985 Bitmap *tmp_bitmap_4;
986 Bitmap *tmp_bitmap_8;
987 Bitmap *tmp_bitmap_16;
988 Bitmap *tmp_bitmap_32;
989 int width_1, height_1;
990 int width_2, height_2;
991 int width_4, height_4;
992 int width_8, height_8;
993 int width_16, height_16;
994 int width_32, height_32;
995 int new_width, new_height;
997 /* calculate new image dimensions for normal sized image */
998 width_1 = old_bitmap->width * zoom_factor;
999 height_1 = old_bitmap->height * zoom_factor;
1001 /* get image with normal size (this might require scaling up) */
1002 if (zoom_factor != 1)
1003 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1005 tmp_bitmap_1 = old_bitmap;
1007 /* this is only needed to make compilers happy */
1008 tmp_bitmap_2 = NULL;
1009 tmp_bitmap_4 = NULL;
1010 tmp_bitmap_8 = NULL;
1011 tmp_bitmap_16 = NULL;
1012 tmp_bitmap_32 = NULL;
1014 if (create_small_bitmaps)
1016 /* calculate new image dimensions for small images */
1017 width_2 = width_1 / 2;
1018 height_2 = height_1 / 2;
1019 width_4 = width_1 / 4;
1020 height_4 = height_1 / 4;
1021 width_8 = width_1 / 8;
1022 height_8 = height_1 / 8;
1023 width_16 = width_1 / 16;
1024 height_16 = height_1 / 16;
1025 width_32 = width_1 / 32;
1026 height_32 = height_1 / 32;
1028 UPDATE_BUSY_STATE();
1030 /* get image with 1/2 of normal size (for use in the level editor) */
1031 if (zoom_factor != 2)
1032 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1034 tmp_bitmap_2 = old_bitmap;
1036 UPDATE_BUSY_STATE();
1038 /* get image with 1/4 of normal size (for use in the level editor) */
1039 if (zoom_factor != 4)
1040 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1042 tmp_bitmap_4 = old_bitmap;
1044 UPDATE_BUSY_STATE();
1046 /* get image with 1/8 of normal size (for use on the preview screen) */
1047 if (zoom_factor != 8)
1048 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1050 tmp_bitmap_8 = old_bitmap;
1052 UPDATE_BUSY_STATE();
1054 /* get image with 1/16 of normal size (for use on the preview screen) */
1055 if (zoom_factor != 16)
1056 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1058 tmp_bitmap_16 = old_bitmap;
1060 UPDATE_BUSY_STATE();
1062 /* get image with 1/32 of normal size (for use on the preview screen) */
1063 if (zoom_factor != 32)
1064 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1066 tmp_bitmap_32 = old_bitmap;
1068 UPDATE_BUSY_STATE();
1072 /* if image was scaled up, create new clipmask for normal size image */
1073 if (zoom_factor != 1)
1075 #if defined(TARGET_X11)
1076 if (old_bitmap->clip_mask)
1077 XFreePixmap(display, old_bitmap->clip_mask);
1079 old_bitmap->clip_mask =
1080 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1082 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1084 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1086 if (old_bitmap->surface_masked)
1087 SDL_FreeSurface(old_bitmap->surface_masked);
1089 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1090 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1091 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1092 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1093 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1098 if (create_small_bitmaps)
1100 new_width = width_1;
1101 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1103 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1105 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1106 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1108 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1109 width_1 / 2, height_1);
1110 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1111 3 * width_1 / 4, height_1);
1112 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1113 7 * width_1 / 8, height_1);
1114 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1115 15 * width_1 / 16, height_1);
1117 UPDATE_BUSY_STATE();
1121 new_width = width_1;
1122 new_height = height_1;
1124 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1127 if (create_small_bitmaps)
1129 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1130 if (zoom_factor != 1)
1131 FreeBitmap(tmp_bitmap_1);
1133 if (zoom_factor != 2)
1134 FreeBitmap(tmp_bitmap_2);
1136 if (zoom_factor != 4)
1137 FreeBitmap(tmp_bitmap_4);
1139 if (zoom_factor != 8)
1140 FreeBitmap(tmp_bitmap_8);
1142 if (zoom_factor != 16)
1143 FreeBitmap(tmp_bitmap_16);
1145 if (zoom_factor != 32)
1146 FreeBitmap(tmp_bitmap_32);
1149 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1150 #if defined(TARGET_SDL)
1151 swap_bitmap.surface = old_bitmap->surface;
1152 old_bitmap->surface = new_bitmap->surface;
1153 new_bitmap->surface = swap_bitmap.surface;
1155 swap_bitmap.drawable = old_bitmap->drawable;
1156 old_bitmap->drawable = new_bitmap->drawable;
1157 new_bitmap->drawable = swap_bitmap.drawable;
1160 old_bitmap->width = new_bitmap->width;
1161 old_bitmap->height = new_bitmap->height;
1164 /* this replaces all blit masks created when loading -- maybe optimize this */
1166 #if defined(TARGET_X11)
1167 if (old_bitmap->clip_mask)
1168 XFreePixmap(display, old_bitmap->clip_mask);
1170 old_bitmap->clip_mask =
1171 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1173 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1175 SDL_Surface *old_surface = old_bitmap->surface;
1177 if (old_bitmap->surface_masked)
1178 SDL_FreeSurface(old_bitmap->surface_masked);
1180 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1181 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1182 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1183 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1184 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1189 UPDATE_BUSY_STATE();
1191 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1194 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1196 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1199 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1201 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1205 /* ------------------------------------------------------------------------- */
1206 /* mouse pointer functions */
1207 /* ------------------------------------------------------------------------- */
1209 #if !defined(PLATFORM_MSDOS)
1210 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1211 /* XPM image definitions */
1212 static const char *cursor_image_none[] =
1214 /* width height num_colors chars_per_pixel */
1243 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1244 static const char *cursor_image_dot[] =
1246 /* width height num_colors chars_per_pixel */
1275 static const char **cursor_image_playfield = cursor_image_dot;
1277 /* some people complained about a "white dot" on the screen and thought it
1278 was a graphical error... OK, let's just remove the whole pointer :-) */
1279 static const char **cursor_image_playfield = cursor_image_none;
1282 #if defined(TARGET_SDL)
1283 static const int cursor_bit_order = BIT_ORDER_MSB;
1284 #elif defined(TARGET_X11_NATIVE)
1285 static const int cursor_bit_order = BIT_ORDER_LSB;
1288 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1290 struct MouseCursorInfo *cursor;
1291 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1292 int header_lines = 4;
1295 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1297 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1300 for (y = 0; y < cursor->width; y++)
1302 for (x = 0; x < cursor->height; x++)
1305 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1310 cursor->data[i] = cursor->mask[i] = 0;
1313 switch (image[header_lines + y][x])
1316 cursor->data[i] |= bit_mask;
1317 cursor->mask[i] |= bit_mask;
1321 cursor->mask[i] |= bit_mask;
1330 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1334 #endif /* !PLATFORM_MSDOS */
1336 void SetMouseCursor(int mode)
1338 #if !defined(PLATFORM_MSDOS)
1339 static struct MouseCursorInfo *cursor_none = NULL;
1340 static struct MouseCursorInfo *cursor_playfield = NULL;
1341 struct MouseCursorInfo *cursor_new;
1343 if (cursor_none == NULL)
1344 cursor_none = get_cursor_from_image(cursor_image_none);
1346 if (cursor_playfield == NULL)
1347 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1349 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1350 mode == CURSOR_NONE ? cursor_none :
1351 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1353 #if defined(TARGET_SDL)
1354 SDLSetMouseCursor(cursor_new);
1355 #elif defined(TARGET_X11_NATIVE)
1356 X11SetMouseCursor(cursor_new);
1362 /* ========================================================================= */
1363 /* audio functions */
1364 /* ========================================================================= */
1366 void OpenAudio(void)
1368 /* always start with reliable default values */
1369 audio.sound_available = FALSE;
1370 audio.music_available = FALSE;
1371 audio.loops_available = FALSE;
1373 audio.sound_enabled = FALSE;
1374 audio.sound_deactivated = FALSE;
1376 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1377 audio.mixer_pid = 0;
1378 audio.device_name = NULL;
1379 audio.device_fd = -1;
1381 audio.num_channels = 0;
1382 audio.music_channel = 0;
1383 audio.first_sound_channel = 0;
1385 #if defined(TARGET_SDL)
1387 #elif defined(PLATFORM_UNIX)
1389 #elif defined(PLATFORM_MSDOS)
1394 void CloseAudio(void)
1396 #if defined(TARGET_SDL)
1398 #elif defined(PLATFORM_UNIX)
1400 #elif defined(PLATFORM_MSDOS)
1404 audio.sound_enabled = FALSE;
1407 void SetAudioMode(boolean enabled)
1409 if (!audio.sound_available)
1412 audio.sound_enabled = enabled;
1416 /* ========================================================================= */
1417 /* event functions */
1418 /* ========================================================================= */
1420 void InitEventFilter(EventFilter filter_function)
1422 #if defined(TARGET_SDL)
1423 /* set event filter to filter out certain events */
1424 SDL_SetEventFilter(filter_function);
1428 boolean PendingEvent(void)
1430 #if defined(TARGET_SDL)
1431 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1433 return (XPending(display) ? TRUE : FALSE);
1437 void NextEvent(Event *event)
1439 #if defined(TARGET_SDL)
1440 SDLNextEvent(event);
1442 XNextEvent(display, event);
1446 void PeekEvent(Event *event)
1448 #if defined(TARGET_SDL)
1449 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1451 XPeekEvent(display, event);
1455 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1457 #if defined(TARGET_SDL)
1460 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1461 (int)event->keysym.unicode,
1462 (int)event->keysym.sym,
1463 (int)SDL_GetModState());
1466 if (with_modifiers &&
1467 event->keysym.unicode > 0x0000 &&
1468 event->keysym.unicode < 0x2000)
1469 return event->keysym.unicode;
1471 return event->keysym.sym;
1476 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1477 (int)XLookupKeysym(event, event->state),
1478 (int)XLookupKeysym(event, 0));
1482 return XLookupKeysym(event, event->state);
1484 return XLookupKeysym(event, 0);
1488 KeyMod HandleKeyModState(Key key, int key_status)
1490 static KeyMod current_modifiers = KMOD_None;
1492 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1494 KeyMod new_modifier = KMOD_None;
1499 new_modifier = KMOD_Shift_L;
1502 new_modifier = KMOD_Shift_R;
1504 case KSYM_Control_L:
1505 new_modifier = KMOD_Control_L;
1507 case KSYM_Control_R:
1508 new_modifier = KMOD_Control_R;
1511 new_modifier = KMOD_Meta_L;
1514 new_modifier = KMOD_Meta_R;
1517 new_modifier = KMOD_Alt_L;
1520 new_modifier = KMOD_Alt_R;
1526 if (key_status == KEY_PRESSED)
1527 current_modifiers |= new_modifier;
1529 current_modifiers &= ~new_modifier;
1532 return current_modifiers;
1535 KeyMod GetKeyModState()
1537 #if defined(TARGET_SDL)
1538 return (KeyMod)SDL_GetModState();
1540 return HandleKeyModState(KSYM_UNDEFINED, 0);
1544 KeyMod GetKeyModStateFromEvents()
1546 /* always use key modifier state as tracked from key events (this is needed
1547 if the modifier key event was injected into the event queue, but the key
1548 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1549 query the keys as held pressed on the keyboard) -- this case is currently
1550 only used to filter out clipboard insert events from "True X-Mouse" tool */
1552 return HandleKeyModState(KSYM_UNDEFINED, 0);
1555 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1557 if (event->type != EVENT_CLIENTMESSAGE)
1560 #if defined(TARGET_SDL)
1561 return TRUE; /* the only possible message here is SDL_QUIT */
1562 #elif defined(PLATFORM_UNIX)
1563 if ((event->window == window->drawable) &&
1564 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1572 /* ========================================================================= */
1573 /* joystick functions */
1574 /* ========================================================================= */
1576 void InitJoysticks()
1580 #if defined(NO_JOYSTICK)
1581 return; /* joysticks generally deactivated by compile-time directive */
1584 /* always start with reliable default values */
1585 joystick.status = JOYSTICK_NOT_AVAILABLE;
1586 for (i = 0; i < MAX_PLAYERS; i++)
1587 joystick.fd[i] = -1; /* joystick device closed */
1589 #if defined(TARGET_SDL)
1591 #elif defined(PLATFORM_UNIX)
1592 UnixInitJoysticks();
1593 #elif defined(PLATFORM_MSDOS)
1594 MSDOSInitJoysticks();
1598 for (i = 0; i < MAX_PLAYERS; i++)
1599 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1603 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1605 #if defined(TARGET_SDL)
1606 return SDLReadJoystick(nr, x, y, b1, b2);
1607 #elif defined(PLATFORM_UNIX)
1608 return UnixReadJoystick(nr, x, y, b1, b2);
1609 #elif defined(PLATFORM_MSDOS)
1610 return MSDOSReadJoystick(nr, x, y, b1, b2);