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;
169 gfx.background_bitmap = NULL;
170 gfx.background_bitmap_mask = REDRAW_NONE;
172 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
173 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
176 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
184 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
192 void InitGfxWindowInfo(int win_xsize, int win_ysize)
194 gfx.win_xsize = win_xsize;
195 gfx.win_ysize = win_ysize;
198 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
200 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
201 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
202 gfx.scrollbuffer_width = scrollbuffer_width;
203 gfx.scrollbuffer_height = scrollbuffer_height;
206 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
208 gfx.draw_busy_anim_function = draw_busy_anim_function;
211 void InitGfxCustomArtworkInfo()
213 gfx.override_level_graphics = FALSE;
214 gfx.override_level_sounds = FALSE;
215 gfx.override_level_music = FALSE;
217 gfx.draw_init_text = TRUE;
220 void SetDrawDeactivationMask(int draw_deactivation_mask)
222 gfx.draw_deactivation_mask = draw_deactivation_mask;
225 void SetDrawBackgroundMask(int draw_background_mask)
227 gfx.draw_background_mask = draw_background_mask;
230 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
231 int dest_x, int dest_y, int width, int height)
233 int bitmap_xsize = width;
234 int bitmap_ysize = height;
235 int tile_xsize = tile->width;
236 int tile_ysize = tile->height;
237 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
238 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
241 for (y = 0; y < tile_ysteps; y++)
243 for (x = 0; x < tile_xsteps; x++)
245 int draw_x = dest_x + x * tile_xsize;
246 int draw_y = dest_y + y * tile_ysize;
247 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
248 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
250 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
255 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
257 if (background_bitmap_tile != NULL)
258 gfx.background_bitmap_mask |= mask;
260 gfx.background_bitmap_mask &= ~mask;
262 if (gfx.background_bitmap == NULL)
263 gfx.background_bitmap = CreateBitmap(video.width, video.height,
266 if (background_bitmap_tile == NULL) /* empty background requested */
269 if (mask == REDRAW_ALL)
270 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
271 0, 0, video.width, video.height);
272 else if (mask == REDRAW_FIELD)
273 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
274 gfx.real_sx, gfx.real_sy,
275 gfx.full_sxsize, gfx.full_sysize);
276 else if (mask == REDRAW_DOOR_1)
278 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
280 gfx.dxsize, gfx.dysize);
284 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
286 /* remove every mask before setting mask for window */
287 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
288 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
289 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
292 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
294 /* remove window area mask before setting mask for main area */
295 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
296 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
297 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
300 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
302 /* remove window area mask before setting mask for door area */
303 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
304 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
305 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
309 /* ========================================================================= */
310 /* video functions */
311 /* ========================================================================= */
313 inline static int GetRealDepth(int depth)
315 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
318 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
319 int width, int height, Pixel color)
321 #if defined(TARGET_SDL)
322 SDLFillRectangle(bitmap, x, y, width, height, color);
324 X11FillRectangle(bitmap, x, y, width, height, color);
328 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
329 int src_x, int src_y, int width, int height,
330 int dst_x, int dst_y, int mask_mode)
332 #if defined(TARGET_SDL)
333 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
334 dst_x, dst_y, mask_mode);
336 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
337 dst_x, dst_y, mask_mode);
341 void InitVideoDisplay(void)
343 #if defined(TARGET_SDL)
344 SDLInitVideoDisplay();
346 X11InitVideoDisplay();
350 void CloseVideoDisplay(void)
352 KeyboardAutoRepeatOn();
354 #if defined(TARGET_SDL)
355 SDL_QuitSubSystem(SDL_INIT_VIDEO);
358 XCloseDisplay(display);
362 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
365 video.height = height;
366 video.depth = GetRealDepth(depth);
368 video.fullscreen_available = FULLSCREEN_STATUS;
369 video.fullscreen_enabled = FALSE;
370 video.fullscreen_modes = NULL;
371 video.fullscreen_mode_current = NULL;
373 #if defined(TARGET_SDL)
374 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
376 X11InitVideoBuffer(&backbuffer, &window);
382 Bitmap *CreateBitmapStruct(void)
384 #if defined(TARGET_SDL)
385 return checked_calloc(sizeof(struct SDLSurfaceInfo));
387 return checked_calloc(sizeof(struct X11DrawableInfo));
391 Bitmap *CreateBitmap(int width, int height, int depth)
393 Bitmap *new_bitmap = CreateBitmapStruct();
394 int real_width = MAX(1, width); /* prevent zero bitmap width */
395 int real_height = MAX(1, height); /* prevent zero bitmap height */
396 int real_depth = GetRealDepth(depth);
398 #if defined(TARGET_SDL)
399 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
401 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
404 new_bitmap->width = real_width;
405 new_bitmap->height = real_height;
410 inline static void FreeBitmapPointers(Bitmap *bitmap)
415 #if defined(TARGET_SDL)
416 SDLFreeBitmapPointers(bitmap);
418 X11FreeBitmapPointers(bitmap);
421 checked_free(bitmap->source_filename);
422 bitmap->source_filename = NULL;
425 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
428 if (src_bitmap == NULL || dst_bitmap == NULL)
431 FreeBitmapPointers(dst_bitmap);
433 *dst_bitmap = *src_bitmap;
436 void FreeBitmap(Bitmap *bitmap)
441 FreeBitmapPointers(bitmap);
446 void CloseWindow(DrawWindow *window)
448 #if defined(TARGET_X11)
449 if (window->drawable)
451 XUnmapWindow(display, window->drawable);
452 XDestroyWindow(display, window->drawable);
455 XFreeGC(display, window->gc);
459 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
462 if (draw_mask == REDRAW_NONE)
465 if (draw_mask & REDRAW_ALL)
468 if ((draw_mask & REDRAW_FIELD) &&
469 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
472 if ((draw_mask & REDRAW_DOOR_1) &&
473 x >= gfx.dx && y < gfx.dy + gfx.dysize)
476 if ((draw_mask & REDRAW_DOOR_2) &&
477 x >= gfx.dx && y >= gfx.vy)
483 boolean DrawingDeactivated(int x, int y, int width, int height)
485 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
488 boolean DrawingOnBackground(int x, int y)
490 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
491 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
494 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
495 int src_x, int src_y, int width, int height,
496 int dst_x, int dst_y)
498 if (DrawingDeactivated(dst_x, dst_y, width, height))
502 /* !!! 2009-03-24: It seems that this problem still exists with 1.2.12 !!! */
503 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
504 if (src_bitmap == dst_bitmap)
506 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
508 /* needed when blitting directly to same bitmap -- should not be needed with
509 recent SDL libraries, but apparently does not work in 1.2.11 directly */
511 static Bitmap *tmp_bitmap = NULL;
512 static int tmp_bitmap_xsize = 0;
513 static int tmp_bitmap_ysize = 0;
515 /* start with largest static bitmaps for initial bitmap size ... */
516 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
518 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
519 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
522 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
523 if (src_bitmap->width > tmp_bitmap_xsize ||
524 src_bitmap->height > tmp_bitmap_ysize)
526 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
527 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
529 FreeBitmap(tmp_bitmap);
534 if (tmp_bitmap == NULL)
535 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
538 sysCopyArea(src_bitmap, tmp_bitmap,
539 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
540 sysCopyArea(tmp_bitmap, dst_bitmap,
541 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
548 sysCopyArea(src_bitmap, dst_bitmap,
549 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
552 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
553 int fade_mode, int fade_delay, int post_delay,
554 void (*draw_border_function)(void))
556 #if defined(TARGET_SDL)
557 SDLFadeRectangle(bitmap_cross, x, y, width, height,
558 fade_mode, fade_delay, post_delay, draw_border_function);
560 X11FadeRectangle(bitmap_cross, x, y, width, height,
561 fade_mode, fade_delay, post_delay, draw_border_function);
565 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
568 if (DrawingDeactivated(x, y, width, height))
571 sysFillRectangle(bitmap, x, y, width, height, color);
574 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
576 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
579 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
580 int width, int height)
582 if (DrawingOnBackground(x, y))
583 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
585 ClearRectangle(bitmap, x, y, width, height);
588 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
590 #if defined(TARGET_X11)
593 bitmap->clip_gc = clip_gc;
594 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
599 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
601 #if defined(TARGET_X11)
604 bitmap->clip_gc = clip_gc;
605 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
610 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
611 int src_x, int src_y, int width, int height,
612 int dst_x, int dst_y)
614 if (DrawingDeactivated(dst_x, dst_y, width, height))
617 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
618 dst_x, dst_y, BLIT_MASKED);
621 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
622 int src_x, int src_y, int width, int height,
623 int dst_x, int dst_y)
625 if (DrawingOnBackground(dst_x, dst_y))
627 /* draw background */
628 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
631 /* draw foreground */
632 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
633 dst_x - src_x, dst_y - src_y);
634 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
638 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
642 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
645 #if defined(TARGET_SDL)
646 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
648 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
652 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
655 #if defined(TARGET_SDL)
656 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
658 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
662 #if !defined(TARGET_X11_NATIVE)
663 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
664 int to_x, int to_y, Pixel pixel, int line_width)
668 for (x = 0; x < line_width; x++)
670 for (y = 0; y < line_width; y++)
672 int dx = x - line_width / 2;
673 int dy = y - line_width / 2;
675 if ((x == 0 && y == 0) ||
676 (x == 0 && y == line_width - 1) ||
677 (x == line_width - 1 && y == 0) ||
678 (x == line_width - 1 && y == line_width - 1))
681 #if defined(TARGET_SDL)
683 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
684 #elif defined(TARGET_ALLEGRO)
685 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
686 to_x + dx, to_y + dy, pixel);
693 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
695 #if !defined(TARGET_X11_NATIVE)
699 for (i = 0; i < num_points - 1; i++)
700 DrawLine(bitmap, points[i].x, points[i].y,
701 points[i + 1].x, points[i + 1].y, pixel, line_width);
704 SDLDrawLines(bitmap->surface, points, num_points, pixel);
707 XSetForeground(display, bitmap->line_gc[1], pixel);
708 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
709 (XPoint *)points, num_points, CoordModeOrigin);
713 Pixel GetPixel(Bitmap *bitmap, int x, int y)
715 if (x < 0 || x >= bitmap->width ||
716 y < 0 || y >= bitmap->height)
719 #if defined(TARGET_SDL)
720 return SDLGetPixel(bitmap, x, y);
721 #elif defined(TARGET_ALLEGRO)
722 return AllegroGetPixel(bitmap->drawable, x, y);
724 return X11GetPixel(bitmap, x, y);
728 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
729 unsigned int color_g, unsigned int color_b)
731 #if defined(TARGET_SDL)
732 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
733 #elif defined(TARGET_ALLEGRO)
734 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
736 return X11GetPixelFromRGB(color_r, color_g, color_b);
740 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
742 unsigned int color_r = (color >> 16) & 0xff;
743 unsigned int color_g = (color >> 8) & 0xff;
744 unsigned int color_b = (color >> 0) & 0xff;
746 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
749 /* execute all pending screen drawing operations */
750 void FlushDisplay(void)
757 /* execute and wait for all pending screen drawing operations */
758 void SyncDisplay(void)
761 XSync(display, FALSE);
765 void KeyboardAutoRepeatOn(void)
767 #if defined(TARGET_SDL)
768 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
769 SDL_DEFAULT_REPEAT_INTERVAL / 2);
770 SDL_EnableUNICODE(1);
773 XAutoRepeatOn(display);
777 void KeyboardAutoRepeatOff(void)
779 #if defined(TARGET_SDL)
780 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
781 SDL_EnableUNICODE(0);
784 XAutoRepeatOff(display);
788 boolean PointerInWindow(DrawWindow *window)
790 #if defined(TARGET_SDL)
798 /* if XQueryPointer() returns False, the pointer
799 is not on the same screen as the specified window */
800 return XQueryPointer(display, window->drawable, &root, &child,
801 &root_x, &root_y, &win_x, &win_y, &mask);
805 boolean SetVideoMode(boolean fullscreen)
807 #if defined(TARGET_SDL)
808 return SDLSetVideoMode(&backbuffer, fullscreen);
810 boolean success = TRUE;
812 if (fullscreen && video.fullscreen_available)
814 Error(ERR_WARN, "fullscreen not available in X11 version");
816 /* display error message only once */
817 video.fullscreen_available = FALSE;
826 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
828 #if defined(TARGET_SDL)
829 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
830 (!fullscreen && video.fullscreen_enabled))
831 fullscreen = SetVideoMode(fullscreen);
837 Bitmap *LoadImage(char *filename)
841 #if defined(TARGET_SDL)
842 new_bitmap = SDLLoadImage(filename);
844 new_bitmap = X11LoadImage(filename);
848 new_bitmap->source_filename = getStringCopy(filename);
853 Bitmap *LoadCustomImage(char *basename)
855 char *filename = getCustomImageFilename(basename);
858 if (filename == NULL)
859 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
861 if ((new_bitmap = LoadImage(filename)) == NULL)
862 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
867 void ReloadCustomImage(Bitmap *bitmap, char *basename)
869 char *filename = getCustomImageFilename(basename);
872 if (filename == NULL) /* (should never happen) */
874 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
878 if (strEqual(filename, bitmap->source_filename))
880 /* The old and new image are the same (have the same filename and path).
881 This usually means that this image does not exist in this graphic set
882 and a fallback to the existing image is done. */
887 if ((new_bitmap = LoadImage(filename)) == NULL)
889 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
893 if (bitmap->width != new_bitmap->width ||
894 bitmap->height != new_bitmap->height)
896 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
898 FreeBitmap(new_bitmap);
902 TransferBitmapPointers(new_bitmap, bitmap);
906 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
908 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
910 #if defined(TARGET_SDL)
911 SDLZoomBitmap(src_bitmap, dst_bitmap);
913 X11ZoomBitmap(src_bitmap, dst_bitmap);
919 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
920 boolean create_small_bitmaps)
924 Bitmap *tmp_bitmap_1;
925 Bitmap *tmp_bitmap_2;
926 Bitmap *tmp_bitmap_4;
927 Bitmap *tmp_bitmap_8;
928 Bitmap *tmp_bitmap_16;
929 Bitmap *tmp_bitmap_32;
930 int width_1, height_1;
931 int width_2, height_2;
932 int width_4, height_4;
933 int width_8, height_8;
934 int width_16, height_16;
935 int width_32, height_32;
936 int new_width, new_height;
938 /* calculate new image dimensions for normal sized image */
939 width_1 = old_bitmap->width * zoom_factor;
940 height_1 = old_bitmap->height * zoom_factor;
942 /* get image with normal size (this might require scaling up) */
943 if (zoom_factor != 1)
944 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
946 tmp_bitmap_1 = old_bitmap;
948 /* this is only needed to make compilers happy */
952 tmp_bitmap_16 = NULL;
953 tmp_bitmap_32 = NULL;
955 if (create_small_bitmaps)
957 /* calculate new image dimensions for small images */
958 width_2 = width_1 / 2;
959 height_2 = height_1 / 2;
960 width_4 = width_1 / 4;
961 height_4 = height_1 / 4;
962 width_8 = width_1 / 8;
963 height_8 = height_1 / 8;
964 width_16 = width_1 / 16;
965 height_16 = height_1 / 16;
966 width_32 = width_1 / 32;
967 height_32 = height_1 / 32;
971 /* get image with 1/2 of normal size (for use in the level editor) */
972 if (zoom_factor != 2)
973 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
975 tmp_bitmap_2 = old_bitmap;
979 /* get image with 1/4 of normal size (for use in the level editor) */
980 if (zoom_factor != 4)
981 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
983 tmp_bitmap_4 = old_bitmap;
987 /* get image with 1/8 of normal size (for use on the preview screen) */
988 if (zoom_factor != 8)
989 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
991 tmp_bitmap_8 = old_bitmap;
995 /* get image with 1/16 of normal size (for use on the preview screen) */
996 if (zoom_factor != 16)
997 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
999 tmp_bitmap_16 = old_bitmap;
1001 UPDATE_BUSY_STATE();
1003 /* get image with 1/32 of normal size (for use on the preview screen) */
1004 if (zoom_factor != 32)
1005 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1007 tmp_bitmap_32 = old_bitmap;
1009 UPDATE_BUSY_STATE();
1013 /* if image was scaled up, create new clipmask for normal size image */
1014 if (zoom_factor != 1)
1016 #if defined(TARGET_X11)
1017 if (old_bitmap->clip_mask)
1018 XFreePixmap(display, old_bitmap->clip_mask);
1020 old_bitmap->clip_mask =
1021 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1023 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1025 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1027 if (old_bitmap->surface_masked)
1028 SDL_FreeSurface(old_bitmap->surface_masked);
1030 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1031 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1032 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1033 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1034 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1039 if (create_small_bitmaps)
1041 new_width = width_1;
1042 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1044 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1046 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1047 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1049 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1050 width_1 / 2, height_1);
1051 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1052 3 * width_1 / 4, height_1);
1053 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1054 7 * width_1 / 8, height_1);
1055 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1056 15 * width_1 / 16, height_1);
1058 UPDATE_BUSY_STATE();
1062 new_width = width_1;
1063 new_height = height_1;
1065 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1068 if (create_small_bitmaps)
1070 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1071 if (zoom_factor != 1)
1072 FreeBitmap(tmp_bitmap_1);
1074 if (zoom_factor != 2)
1075 FreeBitmap(tmp_bitmap_2);
1077 if (zoom_factor != 4)
1078 FreeBitmap(tmp_bitmap_4);
1080 if (zoom_factor != 8)
1081 FreeBitmap(tmp_bitmap_8);
1083 if (zoom_factor != 16)
1084 FreeBitmap(tmp_bitmap_16);
1086 if (zoom_factor != 32)
1087 FreeBitmap(tmp_bitmap_32);
1090 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1091 #if defined(TARGET_SDL)
1092 swap_bitmap.surface = old_bitmap->surface;
1093 old_bitmap->surface = new_bitmap->surface;
1094 new_bitmap->surface = swap_bitmap.surface;
1096 swap_bitmap.drawable = old_bitmap->drawable;
1097 old_bitmap->drawable = new_bitmap->drawable;
1098 new_bitmap->drawable = swap_bitmap.drawable;
1101 old_bitmap->width = new_bitmap->width;
1102 old_bitmap->height = new_bitmap->height;
1105 /* this replaces all blit masks created when loading -- maybe optimize this */
1107 #if defined(TARGET_X11)
1108 if (old_bitmap->clip_mask)
1109 XFreePixmap(display, old_bitmap->clip_mask);
1111 old_bitmap->clip_mask =
1112 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1114 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1116 SDL_Surface *old_surface = old_bitmap->surface;
1118 if (old_bitmap->surface_masked)
1119 SDL_FreeSurface(old_bitmap->surface_masked);
1121 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1122 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1123 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1124 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1125 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1130 UPDATE_BUSY_STATE();
1132 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1135 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1137 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1140 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1142 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1146 /* ------------------------------------------------------------------------- */
1147 /* mouse pointer functions */
1148 /* ------------------------------------------------------------------------- */
1150 #if !defined(PLATFORM_MSDOS)
1151 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1152 /* XPM image definitions */
1153 static const char *cursor_image_none[] =
1155 /* width height num_colors chars_per_pixel */
1184 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1185 static const char *cursor_image_dot[] =
1187 /* width height num_colors chars_per_pixel */
1216 static const char **cursor_image_playfield = cursor_image_dot;
1218 /* some people complained about a "white dot" on the screen and thought it
1219 was a graphical error... OK, let's just remove the whole pointer :-) */
1220 static const char **cursor_image_playfield = cursor_image_none;
1223 #if defined(TARGET_SDL)
1224 static const int cursor_bit_order = BIT_ORDER_MSB;
1225 #elif defined(TARGET_X11_NATIVE)
1226 static const int cursor_bit_order = BIT_ORDER_LSB;
1229 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1231 struct MouseCursorInfo *cursor;
1232 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1233 int header_lines = 4;
1236 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1238 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1241 for (y = 0; y < cursor->width; y++)
1243 for (x = 0; x < cursor->height; x++)
1246 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1251 cursor->data[i] = cursor->mask[i] = 0;
1254 switch (image[header_lines + y][x])
1257 cursor->data[i] |= bit_mask;
1258 cursor->mask[i] |= bit_mask;
1262 cursor->mask[i] |= bit_mask;
1271 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1275 #endif /* !PLATFORM_MSDOS */
1277 void SetMouseCursor(int mode)
1279 #if !defined(PLATFORM_MSDOS)
1280 static struct MouseCursorInfo *cursor_none = NULL;
1281 static struct MouseCursorInfo *cursor_playfield = NULL;
1282 struct MouseCursorInfo *cursor_new;
1284 if (cursor_none == NULL)
1285 cursor_none = get_cursor_from_image(cursor_image_none);
1287 if (cursor_playfield == NULL)
1288 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1290 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1291 mode == CURSOR_NONE ? cursor_none :
1292 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1294 #if defined(TARGET_SDL)
1295 SDLSetMouseCursor(cursor_new);
1296 #elif defined(TARGET_X11_NATIVE)
1297 X11SetMouseCursor(cursor_new);
1303 /* ========================================================================= */
1304 /* audio functions */
1305 /* ========================================================================= */
1307 void OpenAudio(void)
1309 /* always start with reliable default values */
1310 audio.sound_available = FALSE;
1311 audio.music_available = FALSE;
1312 audio.loops_available = FALSE;
1314 audio.sound_enabled = FALSE;
1315 audio.sound_deactivated = FALSE;
1317 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1318 audio.mixer_pid = 0;
1319 audio.device_name = NULL;
1320 audio.device_fd = -1;
1322 audio.num_channels = 0;
1323 audio.music_channel = 0;
1324 audio.first_sound_channel = 0;
1326 #if defined(TARGET_SDL)
1328 #elif defined(PLATFORM_UNIX)
1330 #elif defined(PLATFORM_MSDOS)
1335 void CloseAudio(void)
1337 #if defined(TARGET_SDL)
1339 #elif defined(PLATFORM_UNIX)
1341 #elif defined(PLATFORM_MSDOS)
1345 audio.sound_enabled = FALSE;
1348 void SetAudioMode(boolean enabled)
1350 if (!audio.sound_available)
1353 audio.sound_enabled = enabled;
1357 /* ========================================================================= */
1358 /* event functions */
1359 /* ========================================================================= */
1361 void InitEventFilter(EventFilter filter_function)
1363 #if defined(TARGET_SDL)
1364 /* set event filter to filter out certain events */
1365 SDL_SetEventFilter(filter_function);
1369 boolean PendingEvent(void)
1371 #if defined(TARGET_SDL)
1372 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1374 return (XPending(display) ? TRUE : FALSE);
1378 void NextEvent(Event *event)
1380 #if defined(TARGET_SDL)
1381 SDLNextEvent(event);
1383 XNextEvent(display, event);
1387 void PeekEvent(Event *event)
1389 #if defined(TARGET_SDL)
1390 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1392 XPeekEvent(display, event);
1396 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1398 #if defined(TARGET_SDL)
1401 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1402 (int)event->keysym.unicode,
1403 (int)event->keysym.sym,
1404 (int)SDL_GetModState());
1407 if (with_modifiers &&
1408 event->keysym.unicode > 0x0000 &&
1409 event->keysym.unicode < 0x2000)
1410 return event->keysym.unicode;
1412 return event->keysym.sym;
1417 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1418 (int)XLookupKeysym(event, event->state),
1419 (int)XLookupKeysym(event, 0));
1423 return XLookupKeysym(event, event->state);
1425 return XLookupKeysym(event, 0);
1429 KeyMod HandleKeyModState(Key key, int key_status)
1431 static KeyMod current_modifiers = KMOD_None;
1433 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1435 KeyMod new_modifier = KMOD_None;
1440 new_modifier = KMOD_Shift_L;
1443 new_modifier = KMOD_Shift_R;
1445 case KSYM_Control_L:
1446 new_modifier = KMOD_Control_L;
1448 case KSYM_Control_R:
1449 new_modifier = KMOD_Control_R;
1452 new_modifier = KMOD_Meta_L;
1455 new_modifier = KMOD_Meta_R;
1458 new_modifier = KMOD_Alt_L;
1461 new_modifier = KMOD_Alt_R;
1467 if (key_status == KEY_PRESSED)
1468 current_modifiers |= new_modifier;
1470 current_modifiers &= ~new_modifier;
1473 return current_modifiers;
1476 KeyMod GetKeyModState()
1478 #if defined(TARGET_SDL)
1479 return (KeyMod)SDL_GetModState();
1481 return HandleKeyModState(KSYM_UNDEFINED, 0);
1485 KeyMod GetKeyModStateFromEvents()
1487 /* always use key modifier state as tracked from key events (this is needed
1488 if the modifier key event was injected into the event queue, but the key
1489 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1490 query the keys as held pressed on the keyboard) -- this case is currently
1491 only used to filter out clipboard insert events from "True X-Mouse" tool */
1493 return HandleKeyModState(KSYM_UNDEFINED, 0);
1496 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1498 if (event->type != EVENT_CLIENTMESSAGE)
1501 #if defined(TARGET_SDL)
1502 return TRUE; /* the only possible message here is SDL_QUIT */
1503 #elif defined(PLATFORM_UNIX)
1504 if ((event->window == window->drawable) &&
1505 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1513 /* ========================================================================= */
1514 /* joystick functions */
1515 /* ========================================================================= */
1517 void InitJoysticks()
1521 #if defined(NO_JOYSTICK)
1522 return; /* joysticks generally deactivated by compile-time directive */
1525 /* always start with reliable default values */
1526 joystick.status = JOYSTICK_NOT_AVAILABLE;
1527 for (i = 0; i < MAX_PLAYERS; i++)
1528 joystick.fd[i] = -1; /* joystick device closed */
1530 #if defined(TARGET_SDL)
1532 #elif defined(PLATFORM_UNIX)
1533 UnixInitJoysticks();
1534 #elif defined(PLATFORM_MSDOS)
1535 MSDOSInitJoysticks();
1539 for (i = 0; i < MAX_PLAYERS; i++)
1540 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1544 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1546 #if defined(TARGET_SDL)
1547 return SDLReadJoystick(nr, x, y, b1, b2);
1548 #elif defined(PLATFORM_UNIX)
1549 return UnixReadJoystick(nr, x, y, b1, b2);
1550 #elif defined(PLATFORM_MSDOS)
1551 return MSDOSReadJoystick(nr, x, y, b1, b2);