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-30: Fixed by using self-compiled, patched SDL.dll !!! */
503 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
504 but is already fixed in SVN and should therefore finally be fixed with
505 the next official SDL release, which is probably version 1.2.14.) */
507 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
508 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
509 if (src_bitmap == dst_bitmap)
511 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
513 /* needed when blitting directly to same bitmap -- should not be needed with
514 recent SDL libraries, but apparently does not work in 1.2.11 directly */
516 static Bitmap *tmp_bitmap = NULL;
517 static int tmp_bitmap_xsize = 0;
518 static int tmp_bitmap_ysize = 0;
520 /* start with largest static bitmaps for initial bitmap size ... */
521 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
523 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
524 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
527 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
528 if (src_bitmap->width > tmp_bitmap_xsize ||
529 src_bitmap->height > tmp_bitmap_ysize)
531 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
532 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
534 FreeBitmap(tmp_bitmap);
539 if (tmp_bitmap == NULL)
540 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
543 sysCopyArea(src_bitmap, tmp_bitmap,
544 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
545 sysCopyArea(tmp_bitmap, dst_bitmap,
546 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
554 sysCopyArea(src_bitmap, dst_bitmap,
555 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
558 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
559 int fade_mode, int fade_delay, int post_delay,
560 void (*draw_border_function)(void))
562 #if defined(TARGET_SDL)
563 SDLFadeRectangle(bitmap_cross, x, y, width, height,
564 fade_mode, fade_delay, post_delay, draw_border_function);
566 X11FadeRectangle(bitmap_cross, x, y, width, height,
567 fade_mode, fade_delay, post_delay, draw_border_function);
571 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
574 if (DrawingDeactivated(x, y, width, height))
577 sysFillRectangle(bitmap, x, y, width, height, color);
580 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
582 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
585 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
586 int width, int height)
588 if (DrawingOnBackground(x, y))
589 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
591 ClearRectangle(bitmap, x, y, width, height);
594 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
596 #if defined(TARGET_X11)
599 bitmap->clip_gc = clip_gc;
600 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
605 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
607 #if defined(TARGET_X11)
610 bitmap->clip_gc = clip_gc;
611 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
616 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
617 int src_x, int src_y, int width, int height,
618 int dst_x, int dst_y)
620 if (DrawingDeactivated(dst_x, dst_y, width, height))
623 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
624 dst_x, dst_y, BLIT_MASKED);
627 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
628 int src_x, int src_y, int width, int height,
629 int dst_x, int dst_y)
631 if (DrawingOnBackground(dst_x, dst_y))
633 /* draw background */
634 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
637 /* draw foreground */
638 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
639 dst_x - src_x, dst_y - src_y);
640 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
644 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
648 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
651 #if defined(TARGET_SDL)
652 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
654 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
658 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
661 #if defined(TARGET_SDL)
662 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
664 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
668 #if !defined(TARGET_X11_NATIVE)
669 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
670 int to_x, int to_y, Pixel pixel, int line_width)
674 for (x = 0; x < line_width; x++)
676 for (y = 0; y < line_width; y++)
678 int dx = x - line_width / 2;
679 int dy = y - line_width / 2;
681 if ((x == 0 && y == 0) ||
682 (x == 0 && y == line_width - 1) ||
683 (x == line_width - 1 && y == 0) ||
684 (x == line_width - 1 && y == line_width - 1))
687 #if defined(TARGET_SDL)
689 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
690 #elif defined(TARGET_ALLEGRO)
691 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
692 to_x + dx, to_y + dy, pixel);
699 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
701 #if !defined(TARGET_X11_NATIVE)
705 for (i = 0; i < num_points - 1; i++)
706 DrawLine(bitmap, points[i].x, points[i].y,
707 points[i + 1].x, points[i + 1].y, pixel, line_width);
710 SDLDrawLines(bitmap->surface, points, num_points, pixel);
713 XSetForeground(display, bitmap->line_gc[1], pixel);
714 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
715 (XPoint *)points, num_points, CoordModeOrigin);
719 Pixel GetPixel(Bitmap *bitmap, int x, int y)
721 if (x < 0 || x >= bitmap->width ||
722 y < 0 || y >= bitmap->height)
725 #if defined(TARGET_SDL)
726 return SDLGetPixel(bitmap, x, y);
727 #elif defined(TARGET_ALLEGRO)
728 return AllegroGetPixel(bitmap->drawable, x, y);
730 return X11GetPixel(bitmap, x, y);
734 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
735 unsigned int color_g, unsigned int color_b)
737 #if defined(TARGET_SDL)
738 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
739 #elif defined(TARGET_ALLEGRO)
740 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
742 return X11GetPixelFromRGB(color_r, color_g, color_b);
746 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
748 unsigned int color_r = (color >> 16) & 0xff;
749 unsigned int color_g = (color >> 8) & 0xff;
750 unsigned int color_b = (color >> 0) & 0xff;
752 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
755 /* execute all pending screen drawing operations */
756 void FlushDisplay(void)
763 /* execute and wait for all pending screen drawing operations */
764 void SyncDisplay(void)
767 XSync(display, FALSE);
771 void KeyboardAutoRepeatOn(void)
773 #if defined(TARGET_SDL)
774 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
775 SDL_DEFAULT_REPEAT_INTERVAL / 2);
776 SDL_EnableUNICODE(1);
779 XAutoRepeatOn(display);
783 void KeyboardAutoRepeatOff(void)
785 #if defined(TARGET_SDL)
786 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
787 SDL_EnableUNICODE(0);
790 XAutoRepeatOff(display);
794 boolean PointerInWindow(DrawWindow *window)
796 #if defined(TARGET_SDL)
804 /* if XQueryPointer() returns False, the pointer
805 is not on the same screen as the specified window */
806 return XQueryPointer(display, window->drawable, &root, &child,
807 &root_x, &root_y, &win_x, &win_y, &mask);
811 boolean SetVideoMode(boolean fullscreen)
813 #if defined(TARGET_SDL)
814 return SDLSetVideoMode(&backbuffer, fullscreen);
816 boolean success = TRUE;
818 if (fullscreen && video.fullscreen_available)
820 Error(ERR_WARN, "fullscreen not available in X11 version");
822 /* display error message only once */
823 video.fullscreen_available = FALSE;
832 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
834 #if defined(TARGET_SDL)
835 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
836 (!fullscreen && video.fullscreen_enabled))
837 fullscreen = SetVideoMode(fullscreen);
843 Bitmap *LoadImage(char *filename)
847 #if defined(TARGET_SDL)
848 new_bitmap = SDLLoadImage(filename);
850 new_bitmap = X11LoadImage(filename);
854 new_bitmap->source_filename = getStringCopy(filename);
859 Bitmap *LoadCustomImage(char *basename)
861 char *filename = getCustomImageFilename(basename);
864 if (filename == NULL)
865 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
867 if ((new_bitmap = LoadImage(filename)) == NULL)
868 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
873 void ReloadCustomImage(Bitmap *bitmap, char *basename)
875 char *filename = getCustomImageFilename(basename);
878 if (filename == NULL) /* (should never happen) */
880 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
884 if (strEqual(filename, bitmap->source_filename))
886 /* The old and new image are the same (have the same filename and path).
887 This usually means that this image does not exist in this graphic set
888 and a fallback to the existing image is done. */
893 if ((new_bitmap = LoadImage(filename)) == NULL)
895 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
899 if (bitmap->width != new_bitmap->width ||
900 bitmap->height != new_bitmap->height)
902 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
904 FreeBitmap(new_bitmap);
908 TransferBitmapPointers(new_bitmap, bitmap);
912 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
914 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
916 #if defined(TARGET_SDL)
917 SDLZoomBitmap(src_bitmap, dst_bitmap);
919 X11ZoomBitmap(src_bitmap, dst_bitmap);
925 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
926 boolean create_small_bitmaps)
930 Bitmap *tmp_bitmap_1;
931 Bitmap *tmp_bitmap_2;
932 Bitmap *tmp_bitmap_4;
933 Bitmap *tmp_bitmap_8;
934 Bitmap *tmp_bitmap_16;
935 Bitmap *tmp_bitmap_32;
936 int width_1, height_1;
937 int width_2, height_2;
938 int width_4, height_4;
939 int width_8, height_8;
940 int width_16, height_16;
941 int width_32, height_32;
942 int new_width, new_height;
944 /* calculate new image dimensions for normal sized image */
945 width_1 = old_bitmap->width * zoom_factor;
946 height_1 = old_bitmap->height * zoom_factor;
948 /* get image with normal size (this might require scaling up) */
949 if (zoom_factor != 1)
950 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
952 tmp_bitmap_1 = old_bitmap;
954 /* this is only needed to make compilers happy */
958 tmp_bitmap_16 = NULL;
959 tmp_bitmap_32 = NULL;
961 if (create_small_bitmaps)
963 /* calculate new image dimensions for small images */
964 width_2 = width_1 / 2;
965 height_2 = height_1 / 2;
966 width_4 = width_1 / 4;
967 height_4 = height_1 / 4;
968 width_8 = width_1 / 8;
969 height_8 = height_1 / 8;
970 width_16 = width_1 / 16;
971 height_16 = height_1 / 16;
972 width_32 = width_1 / 32;
973 height_32 = height_1 / 32;
977 /* get image with 1/2 of normal size (for use in the level editor) */
978 if (zoom_factor != 2)
979 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
981 tmp_bitmap_2 = old_bitmap;
985 /* get image with 1/4 of normal size (for use in the level editor) */
986 if (zoom_factor != 4)
987 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
989 tmp_bitmap_4 = old_bitmap;
993 /* get image with 1/8 of normal size (for use on the preview screen) */
994 if (zoom_factor != 8)
995 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
997 tmp_bitmap_8 = old_bitmap;
1001 /* get image with 1/16 of normal size (for use on the preview screen) */
1002 if (zoom_factor != 16)
1003 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1005 tmp_bitmap_16 = old_bitmap;
1007 UPDATE_BUSY_STATE();
1009 /* get image with 1/32 of normal size (for use on the preview screen) */
1010 if (zoom_factor != 32)
1011 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1013 tmp_bitmap_32 = old_bitmap;
1015 UPDATE_BUSY_STATE();
1019 /* if image was scaled up, create new clipmask for normal size image */
1020 if (zoom_factor != 1)
1022 #if defined(TARGET_X11)
1023 if (old_bitmap->clip_mask)
1024 XFreePixmap(display, old_bitmap->clip_mask);
1026 old_bitmap->clip_mask =
1027 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1029 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1031 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1033 if (old_bitmap->surface_masked)
1034 SDL_FreeSurface(old_bitmap->surface_masked);
1036 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1037 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1038 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1039 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1040 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1045 if (create_small_bitmaps)
1047 new_width = width_1;
1048 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1050 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1052 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1053 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1055 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1056 width_1 / 2, height_1);
1057 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1058 3 * width_1 / 4, height_1);
1059 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1060 7 * width_1 / 8, height_1);
1061 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1062 15 * width_1 / 16, height_1);
1064 UPDATE_BUSY_STATE();
1068 new_width = width_1;
1069 new_height = height_1;
1071 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1074 if (create_small_bitmaps)
1076 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1077 if (zoom_factor != 1)
1078 FreeBitmap(tmp_bitmap_1);
1080 if (zoom_factor != 2)
1081 FreeBitmap(tmp_bitmap_2);
1083 if (zoom_factor != 4)
1084 FreeBitmap(tmp_bitmap_4);
1086 if (zoom_factor != 8)
1087 FreeBitmap(tmp_bitmap_8);
1089 if (zoom_factor != 16)
1090 FreeBitmap(tmp_bitmap_16);
1092 if (zoom_factor != 32)
1093 FreeBitmap(tmp_bitmap_32);
1096 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1097 #if defined(TARGET_SDL)
1098 swap_bitmap.surface = old_bitmap->surface;
1099 old_bitmap->surface = new_bitmap->surface;
1100 new_bitmap->surface = swap_bitmap.surface;
1102 swap_bitmap.drawable = old_bitmap->drawable;
1103 old_bitmap->drawable = new_bitmap->drawable;
1104 new_bitmap->drawable = swap_bitmap.drawable;
1107 old_bitmap->width = new_bitmap->width;
1108 old_bitmap->height = new_bitmap->height;
1111 /* this replaces all blit masks created when loading -- maybe optimize this */
1113 #if defined(TARGET_X11)
1114 if (old_bitmap->clip_mask)
1115 XFreePixmap(display, old_bitmap->clip_mask);
1117 old_bitmap->clip_mask =
1118 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1120 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1122 SDL_Surface *old_surface = old_bitmap->surface;
1124 if (old_bitmap->surface_masked)
1125 SDL_FreeSurface(old_bitmap->surface_masked);
1127 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1128 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1129 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1130 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1131 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1136 UPDATE_BUSY_STATE();
1138 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1141 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1143 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1146 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1148 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1152 /* ------------------------------------------------------------------------- */
1153 /* mouse pointer functions */
1154 /* ------------------------------------------------------------------------- */
1156 #if !defined(PLATFORM_MSDOS)
1157 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1158 /* XPM image definitions */
1159 static const char *cursor_image_none[] =
1161 /* width height num_colors chars_per_pixel */
1190 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1191 static const char *cursor_image_dot[] =
1193 /* width height num_colors chars_per_pixel */
1222 static const char **cursor_image_playfield = cursor_image_dot;
1224 /* some people complained about a "white dot" on the screen and thought it
1225 was a graphical error... OK, let's just remove the whole pointer :-) */
1226 static const char **cursor_image_playfield = cursor_image_none;
1229 #if defined(TARGET_SDL)
1230 static const int cursor_bit_order = BIT_ORDER_MSB;
1231 #elif defined(TARGET_X11_NATIVE)
1232 static const int cursor_bit_order = BIT_ORDER_LSB;
1235 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1237 struct MouseCursorInfo *cursor;
1238 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1239 int header_lines = 4;
1242 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1244 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1247 for (y = 0; y < cursor->width; y++)
1249 for (x = 0; x < cursor->height; x++)
1252 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1257 cursor->data[i] = cursor->mask[i] = 0;
1260 switch (image[header_lines + y][x])
1263 cursor->data[i] |= bit_mask;
1264 cursor->mask[i] |= bit_mask;
1268 cursor->mask[i] |= bit_mask;
1277 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1281 #endif /* !PLATFORM_MSDOS */
1283 void SetMouseCursor(int mode)
1285 #if !defined(PLATFORM_MSDOS)
1286 static struct MouseCursorInfo *cursor_none = NULL;
1287 static struct MouseCursorInfo *cursor_playfield = NULL;
1288 struct MouseCursorInfo *cursor_new;
1290 if (cursor_none == NULL)
1291 cursor_none = get_cursor_from_image(cursor_image_none);
1293 if (cursor_playfield == NULL)
1294 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1296 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1297 mode == CURSOR_NONE ? cursor_none :
1298 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1300 #if defined(TARGET_SDL)
1301 SDLSetMouseCursor(cursor_new);
1302 #elif defined(TARGET_X11_NATIVE)
1303 X11SetMouseCursor(cursor_new);
1309 /* ========================================================================= */
1310 /* audio functions */
1311 /* ========================================================================= */
1313 void OpenAudio(void)
1315 /* always start with reliable default values */
1316 audio.sound_available = FALSE;
1317 audio.music_available = FALSE;
1318 audio.loops_available = FALSE;
1320 audio.sound_enabled = FALSE;
1321 audio.sound_deactivated = FALSE;
1323 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1324 audio.mixer_pid = 0;
1325 audio.device_name = NULL;
1326 audio.device_fd = -1;
1328 audio.num_channels = 0;
1329 audio.music_channel = 0;
1330 audio.first_sound_channel = 0;
1332 #if defined(TARGET_SDL)
1334 #elif defined(PLATFORM_UNIX)
1336 #elif defined(PLATFORM_MSDOS)
1341 void CloseAudio(void)
1343 #if defined(TARGET_SDL)
1345 #elif defined(PLATFORM_UNIX)
1347 #elif defined(PLATFORM_MSDOS)
1351 audio.sound_enabled = FALSE;
1354 void SetAudioMode(boolean enabled)
1356 if (!audio.sound_available)
1359 audio.sound_enabled = enabled;
1363 /* ========================================================================= */
1364 /* event functions */
1365 /* ========================================================================= */
1367 void InitEventFilter(EventFilter filter_function)
1369 #if defined(TARGET_SDL)
1370 /* set event filter to filter out certain events */
1371 SDL_SetEventFilter(filter_function);
1375 boolean PendingEvent(void)
1377 #if defined(TARGET_SDL)
1378 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1380 return (XPending(display) ? TRUE : FALSE);
1384 void NextEvent(Event *event)
1386 #if defined(TARGET_SDL)
1387 SDLNextEvent(event);
1389 XNextEvent(display, event);
1393 void PeekEvent(Event *event)
1395 #if defined(TARGET_SDL)
1396 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1398 XPeekEvent(display, event);
1402 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1404 #if defined(TARGET_SDL)
1407 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1408 (int)event->keysym.unicode,
1409 (int)event->keysym.sym,
1410 (int)SDL_GetModState());
1413 if (with_modifiers &&
1414 event->keysym.unicode > 0x0000 &&
1415 event->keysym.unicode < 0x2000)
1416 return event->keysym.unicode;
1418 return event->keysym.sym;
1423 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1424 (int)XLookupKeysym(event, event->state),
1425 (int)XLookupKeysym(event, 0));
1429 return XLookupKeysym(event, event->state);
1431 return XLookupKeysym(event, 0);
1435 KeyMod HandleKeyModState(Key key, int key_status)
1437 static KeyMod current_modifiers = KMOD_None;
1439 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1441 KeyMod new_modifier = KMOD_None;
1446 new_modifier = KMOD_Shift_L;
1449 new_modifier = KMOD_Shift_R;
1451 case KSYM_Control_L:
1452 new_modifier = KMOD_Control_L;
1454 case KSYM_Control_R:
1455 new_modifier = KMOD_Control_R;
1458 new_modifier = KMOD_Meta_L;
1461 new_modifier = KMOD_Meta_R;
1464 new_modifier = KMOD_Alt_L;
1467 new_modifier = KMOD_Alt_R;
1473 if (key_status == KEY_PRESSED)
1474 current_modifiers |= new_modifier;
1476 current_modifiers &= ~new_modifier;
1479 return current_modifiers;
1482 KeyMod GetKeyModState()
1484 #if defined(TARGET_SDL)
1485 return (KeyMod)SDL_GetModState();
1487 return HandleKeyModState(KSYM_UNDEFINED, 0);
1491 KeyMod GetKeyModStateFromEvents()
1493 /* always use key modifier state as tracked from key events (this is needed
1494 if the modifier key event was injected into the event queue, but the key
1495 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1496 query the keys as held pressed on the keyboard) -- this case is currently
1497 only used to filter out clipboard insert events from "True X-Mouse" tool */
1499 return HandleKeyModState(KSYM_UNDEFINED, 0);
1502 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1504 if (event->type != EVENT_CLIENTMESSAGE)
1507 #if defined(TARGET_SDL)
1508 return TRUE; /* the only possible message here is SDL_QUIT */
1509 #elif defined(PLATFORM_UNIX)
1510 if ((event->window == window->drawable) &&
1511 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1519 /* ========================================================================= */
1520 /* joystick functions */
1521 /* ========================================================================= */
1523 void InitJoysticks()
1527 #if defined(NO_JOYSTICK)
1528 return; /* joysticks generally deactivated by compile-time directive */
1531 /* always start with reliable default values */
1532 joystick.status = JOYSTICK_NOT_AVAILABLE;
1533 for (i = 0; i < MAX_PLAYERS; i++)
1534 joystick.fd[i] = -1; /* joystick device closed */
1536 #if defined(TARGET_SDL)
1538 #elif defined(PLATFORM_UNIX)
1539 UnixInitJoysticks();
1540 #elif defined(PLATFORM_MSDOS)
1541 MSDOSInitJoysticks();
1545 for (i = 0; i < MAX_PLAYERS; i++)
1546 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1550 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1552 #if defined(TARGET_SDL)
1553 return SDLReadJoystick(nr, x, y, b1, b2);
1554 #elif defined(PLATFORM_UNIX)
1555 return UnixReadJoystick(nr, x, y, b1, b2);
1556 #elif defined(PLATFORM_MSDOS)
1557 return MSDOSReadJoystick(nr, x, y, b1, b2);