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 InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
194 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
195 gfx.scrollbuffer_width = scrollbuffer_width;
196 gfx.scrollbuffer_height = scrollbuffer_height;
199 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
201 gfx.draw_busy_anim_function = draw_busy_anim_function;
204 void InitGfxCustomArtworkInfo()
206 gfx.override_level_graphics = FALSE;
207 gfx.override_level_sounds = FALSE;
208 gfx.override_level_music = FALSE;
210 gfx.draw_init_text = TRUE;
213 void SetDrawDeactivationMask(int draw_deactivation_mask)
215 gfx.draw_deactivation_mask = draw_deactivation_mask;
218 void SetDrawBackgroundMask(int draw_background_mask)
220 gfx.draw_background_mask = draw_background_mask;
223 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
224 int dest_x, int dest_y, int width, int height)
226 int bitmap_xsize = width;
227 int bitmap_ysize = height;
228 int tile_xsize = tile->width;
229 int tile_ysize = tile->height;
230 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
231 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
234 for (y = 0; y < tile_ysteps; y++)
236 for (x = 0; x < tile_xsteps; x++)
238 int draw_x = dest_x + x * tile_xsize;
239 int draw_y = dest_y + y * tile_ysize;
240 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
241 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
243 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
248 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
250 if (background_bitmap_tile != NULL)
251 gfx.background_bitmap_mask |= mask;
253 gfx.background_bitmap_mask &= ~mask;
255 if (gfx.background_bitmap == NULL)
256 gfx.background_bitmap = CreateBitmap(video.width, video.height,
259 if (background_bitmap_tile == NULL) /* empty background requested */
262 if (mask == REDRAW_ALL)
263 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
264 0, 0, video.width, video.height);
265 else if (mask == REDRAW_FIELD)
266 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
267 gfx.real_sx, gfx.real_sy,
268 gfx.full_sxsize, gfx.full_sysize);
269 else if (mask == REDRAW_DOOR_1)
271 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
273 gfx.dxsize, gfx.dysize);
277 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
279 /* remove every mask before setting mask for window */
280 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
281 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
282 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
285 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
287 /* remove window area mask before setting mask for main area */
288 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
289 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
290 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
293 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
295 /* remove window area mask before setting mask for door area */
296 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
297 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
298 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
302 /* ========================================================================= */
303 /* video functions */
304 /* ========================================================================= */
306 inline static int GetRealDepth(int depth)
308 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
311 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
312 int width, int height, Pixel color)
314 #if defined(TARGET_SDL)
315 SDLFillRectangle(bitmap, x, y, width, height, color);
317 X11FillRectangle(bitmap, x, y, width, height, color);
321 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
322 int src_x, int src_y, int width, int height,
323 int dst_x, int dst_y, int mask_mode)
325 #if defined(TARGET_SDL)
326 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
327 dst_x, dst_y, mask_mode);
329 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
330 dst_x, dst_y, mask_mode);
334 void InitVideoDisplay(void)
336 #if defined(TARGET_SDL)
337 SDLInitVideoDisplay();
339 X11InitVideoDisplay();
343 void CloseVideoDisplay(void)
345 KeyboardAutoRepeatOn();
347 #if defined(TARGET_SDL)
348 SDL_QuitSubSystem(SDL_INIT_VIDEO);
351 XCloseDisplay(display);
355 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
358 video.height = height;
359 video.depth = GetRealDepth(depth);
361 video.fullscreen_available = FULLSCREEN_STATUS;
362 video.fullscreen_enabled = FALSE;
363 video.fullscreen_modes = NULL;
364 video.fullscreen_mode_current = NULL;
366 #if defined(TARGET_SDL)
367 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
369 X11InitVideoBuffer(&backbuffer, &window);
375 Bitmap *CreateBitmapStruct(void)
377 #if defined(TARGET_SDL)
378 return checked_calloc(sizeof(struct SDLSurfaceInfo));
380 return checked_calloc(sizeof(struct X11DrawableInfo));
384 Bitmap *CreateBitmap(int width, int height, int depth)
386 Bitmap *new_bitmap = CreateBitmapStruct();
387 int real_width = MAX(1, width); /* prevent zero bitmap width */
388 int real_height = MAX(1, height); /* prevent zero bitmap height */
389 int real_depth = GetRealDepth(depth);
391 #if defined(TARGET_SDL)
392 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
394 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
397 new_bitmap->width = real_width;
398 new_bitmap->height = real_height;
403 inline static void FreeBitmapPointers(Bitmap *bitmap)
408 #if defined(TARGET_SDL)
409 SDLFreeBitmapPointers(bitmap);
411 X11FreeBitmapPointers(bitmap);
414 checked_free(bitmap->source_filename);
415 bitmap->source_filename = NULL;
418 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
421 if (src_bitmap == NULL || dst_bitmap == NULL)
424 FreeBitmapPointers(dst_bitmap);
426 *dst_bitmap = *src_bitmap;
429 void FreeBitmap(Bitmap *bitmap)
434 FreeBitmapPointers(bitmap);
439 void CloseWindow(DrawWindow *window)
441 #if defined(TARGET_X11)
442 if (window->drawable)
444 XUnmapWindow(display, window->drawable);
445 XDestroyWindow(display, window->drawable);
448 XFreeGC(display, window->gc);
452 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
455 if (draw_mask == REDRAW_NONE)
458 if (draw_mask & REDRAW_ALL)
461 if ((draw_mask & REDRAW_FIELD) &&
462 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
465 if ((draw_mask & REDRAW_DOOR_1) &&
466 x >= gfx.dx && y < gfx.dy + gfx.dysize)
469 if ((draw_mask & REDRAW_DOOR_2) &&
470 x >= gfx.dx && y >= gfx.vy)
476 boolean DrawingDeactivated(int x, int y, int width, int height)
478 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
481 boolean DrawingOnBackground(int x, int y)
483 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
484 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
487 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
488 int src_x, int src_y, int width, int height,
489 int dst_x, int dst_y)
491 if (DrawingDeactivated(dst_x, dst_y, width, height))
495 /* !!! APPARENTLY THIS HAS BEEN FIXED IN SDL 1.2.12 !!! */
496 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
497 if (src_bitmap == dst_bitmap)
499 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
501 /* needed when blitting directly to same bitmap -- should not be needed with
502 recent SDL libraries, but apparently does not work in 1.2.11 directly */
504 static Bitmap *tmp_bitmap = NULL;
506 if (tmp_bitmap == NULL)
507 tmp_bitmap = CreateBitmap(MAX(FXSIZE, WIN_XSIZE),
508 MAX(FYSIZE, WIN_YSIZE), DEFAULT_DEPTH);
510 sysCopyArea(src_bitmap, tmp_bitmap,
511 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
512 sysCopyArea(tmp_bitmap, dst_bitmap,
513 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
520 sysCopyArea(src_bitmap, dst_bitmap,
521 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
524 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
525 int fade_mode, int fade_delay, int post_delay,
526 void (*draw_border_function)(void))
528 #if defined(TARGET_SDL)
529 SDLFadeRectangle(bitmap_cross, x, y, width, height,
530 fade_mode, fade_delay, post_delay, draw_border_function);
532 X11FadeRectangle(bitmap_cross, x, y, width, height,
533 fade_mode, fade_delay, post_delay, draw_border_function);
537 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
540 if (DrawingDeactivated(x, y, width, height))
543 sysFillRectangle(bitmap, x, y, width, height, color);
546 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
548 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
551 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
552 int width, int height)
554 if (DrawingOnBackground(x, y))
555 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
557 ClearRectangle(bitmap, x, y, width, height);
560 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
562 #if defined(TARGET_X11)
565 bitmap->clip_gc = clip_gc;
566 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
571 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
573 #if defined(TARGET_X11)
576 bitmap->clip_gc = clip_gc;
577 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
582 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
583 int src_x, int src_y, int width, int height,
584 int dst_x, int dst_y)
586 if (DrawingDeactivated(dst_x, dst_y, width, height))
589 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
590 dst_x, dst_y, BLIT_MASKED);
593 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
594 int src_x, int src_y, int width, int height,
595 int dst_x, int dst_y)
597 if (DrawingOnBackground(dst_x, dst_y))
599 /* draw background */
600 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
603 /* draw foreground */
604 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
605 dst_x - src_x, dst_y - src_y);
606 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
610 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
614 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
617 #if defined(TARGET_SDL)
618 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
620 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
624 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
627 #if defined(TARGET_SDL)
628 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
630 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
634 #if !defined(TARGET_X11_NATIVE)
635 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
636 int to_x, int to_y, Pixel pixel, int line_width)
640 for (x = 0; x < line_width; x++)
642 for (y = 0; y < line_width; y++)
644 int dx = x - line_width / 2;
645 int dy = y - line_width / 2;
647 if ((x == 0 && y == 0) ||
648 (x == 0 && y == line_width - 1) ||
649 (x == line_width - 1 && y == 0) ||
650 (x == line_width - 1 && y == line_width - 1))
653 #if defined(TARGET_SDL)
655 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
656 #elif defined(TARGET_ALLEGRO)
657 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
658 to_x + dx, to_y + dy, pixel);
665 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
667 #if !defined(TARGET_X11_NATIVE)
671 for (i = 0; i < num_points - 1; i++)
672 DrawLine(bitmap, points[i].x, points[i].y,
673 points[i + 1].x, points[i + 1].y, pixel, line_width);
676 SDLDrawLines(bitmap->surface, points, num_points, pixel);
679 XSetForeground(display, bitmap->line_gc[1], pixel);
680 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
681 (XPoint *)points, num_points, CoordModeOrigin);
685 Pixel GetPixel(Bitmap *bitmap, int x, int y)
687 if (x < 0 || x >= bitmap->width ||
688 y < 0 || y >= bitmap->height)
691 #if defined(TARGET_SDL)
692 return SDLGetPixel(bitmap, x, y);
693 #elif defined(TARGET_ALLEGRO)
694 return AllegroGetPixel(bitmap->drawable, x, y);
696 return X11GetPixel(bitmap, x, y);
700 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
701 unsigned int color_g, unsigned int color_b)
703 #if defined(TARGET_SDL)
704 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
705 #elif defined(TARGET_ALLEGRO)
706 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
708 return X11GetPixelFromRGB(color_r, color_g, color_b);
712 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
714 unsigned int color_r = (color >> 16) & 0xff;
715 unsigned int color_g = (color >> 8) & 0xff;
716 unsigned int color_b = (color >> 0) & 0xff;
718 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
721 /* execute all pending screen drawing operations */
722 void FlushDisplay(void)
729 /* execute and wait for all pending screen drawing operations */
730 void SyncDisplay(void)
733 XSync(display, FALSE);
737 void KeyboardAutoRepeatOn(void)
739 #if defined(TARGET_SDL)
740 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
741 SDL_DEFAULT_REPEAT_INTERVAL / 2);
742 SDL_EnableUNICODE(1);
745 XAutoRepeatOn(display);
749 void KeyboardAutoRepeatOff(void)
751 #if defined(TARGET_SDL)
752 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
753 SDL_EnableUNICODE(0);
756 XAutoRepeatOff(display);
760 boolean PointerInWindow(DrawWindow *window)
762 #if defined(TARGET_SDL)
770 /* if XQueryPointer() returns False, the pointer
771 is not on the same screen as the specified window */
772 return XQueryPointer(display, window->drawable, &root, &child,
773 &root_x, &root_y, &win_x, &win_y, &mask);
777 boolean SetVideoMode(boolean fullscreen)
779 #if defined(TARGET_SDL)
780 return SDLSetVideoMode(&backbuffer, fullscreen);
782 boolean success = TRUE;
784 if (fullscreen && video.fullscreen_available)
786 Error(ERR_WARN, "fullscreen not available in X11 version");
788 /* display error message only once */
789 video.fullscreen_available = FALSE;
798 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
800 #if defined(TARGET_SDL)
801 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
802 (!fullscreen && video.fullscreen_enabled))
803 fullscreen = SetVideoMode(fullscreen);
809 Bitmap *LoadImage(char *filename)
813 #if defined(TARGET_SDL)
814 new_bitmap = SDLLoadImage(filename);
816 new_bitmap = X11LoadImage(filename);
820 new_bitmap->source_filename = getStringCopy(filename);
825 Bitmap *LoadCustomImage(char *basename)
827 char *filename = getCustomImageFilename(basename);
830 if (filename == NULL)
831 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
833 if ((new_bitmap = LoadImage(filename)) == NULL)
834 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
839 void ReloadCustomImage(Bitmap *bitmap, char *basename)
841 char *filename = getCustomImageFilename(basename);
844 if (filename == NULL) /* (should never happen) */
846 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
850 if (strEqual(filename, bitmap->source_filename))
852 /* The old and new image are the same (have the same filename and path).
853 This usually means that this image does not exist in this graphic set
854 and a fallback to the existing image is done. */
859 if ((new_bitmap = LoadImage(filename)) == NULL)
861 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
865 if (bitmap->width != new_bitmap->width ||
866 bitmap->height != new_bitmap->height)
868 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
870 FreeBitmap(new_bitmap);
874 TransferBitmapPointers(new_bitmap, bitmap);
878 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
880 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
882 #if defined(TARGET_SDL)
883 SDLZoomBitmap(src_bitmap, dst_bitmap);
885 X11ZoomBitmap(src_bitmap, dst_bitmap);
891 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
892 boolean create_small_bitmaps)
896 Bitmap *tmp_bitmap_1;
897 Bitmap *tmp_bitmap_2;
898 Bitmap *tmp_bitmap_4;
899 Bitmap *tmp_bitmap_8;
900 Bitmap *tmp_bitmap_16;
901 Bitmap *tmp_bitmap_32;
902 int width_1, height_1;
903 int width_2, height_2;
904 int width_4, height_4;
905 int width_8, height_8;
906 int width_16, height_16;
907 int width_32, height_32;
908 int new_width, new_height;
910 /* calculate new image dimensions for normal sized image */
911 width_1 = old_bitmap->width * zoom_factor;
912 height_1 = old_bitmap->height * zoom_factor;
914 /* get image with normal size (this might require scaling up) */
915 if (zoom_factor != 1)
916 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
918 tmp_bitmap_1 = old_bitmap;
920 /* this is only needed to make compilers happy */
924 tmp_bitmap_16 = NULL;
925 tmp_bitmap_32 = NULL;
927 if (create_small_bitmaps)
929 /* calculate new image dimensions for small images */
930 width_2 = width_1 / 2;
931 height_2 = height_1 / 2;
932 width_4 = width_1 / 4;
933 height_4 = height_1 / 4;
934 width_8 = width_1 / 8;
935 height_8 = height_1 / 8;
936 width_16 = width_1 / 16;
937 height_16 = height_1 / 16;
938 width_32 = width_1 / 32;
939 height_32 = height_1 / 32;
943 /* get image with 1/2 of normal size (for use in the level editor) */
944 if (zoom_factor != 2)
945 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
947 tmp_bitmap_2 = old_bitmap;
951 /* get image with 1/4 of normal size (for use in the level editor) */
952 if (zoom_factor != 4)
953 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
955 tmp_bitmap_4 = old_bitmap;
959 /* get image with 1/8 of normal size (for use on the preview screen) */
960 if (zoom_factor != 8)
961 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
963 tmp_bitmap_8 = old_bitmap;
967 /* get image with 1/16 of normal size (for use on the preview screen) */
968 if (zoom_factor != 16)
969 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
971 tmp_bitmap_16 = old_bitmap;
975 /* get image with 1/32 of normal size (for use on the preview screen) */
976 if (zoom_factor != 32)
977 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
979 tmp_bitmap_32 = old_bitmap;
985 /* if image was scaled up, create new clipmask for normal size image */
986 if (zoom_factor != 1)
988 #if defined(TARGET_X11)
989 if (old_bitmap->clip_mask)
990 XFreePixmap(display, old_bitmap->clip_mask);
992 old_bitmap->clip_mask =
993 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
995 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
997 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
999 if (old_bitmap->surface_masked)
1000 SDL_FreeSurface(old_bitmap->surface_masked);
1002 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1003 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1004 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1005 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1006 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1011 if (create_small_bitmaps)
1013 new_width = width_1;
1014 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1016 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1018 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1019 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1021 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1022 width_1 / 2, height_1);
1023 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1024 3 * width_1 / 4, height_1);
1025 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1026 7 * width_1 / 8, height_1);
1027 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1028 15 * width_1 / 16, height_1);
1030 UPDATE_BUSY_STATE();
1034 new_width = width_1;
1035 new_height = height_1;
1037 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1040 if (create_small_bitmaps)
1042 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1043 if (zoom_factor != 1)
1044 FreeBitmap(tmp_bitmap_1);
1046 if (zoom_factor != 2)
1047 FreeBitmap(tmp_bitmap_2);
1049 if (zoom_factor != 4)
1050 FreeBitmap(tmp_bitmap_4);
1052 if (zoom_factor != 8)
1053 FreeBitmap(tmp_bitmap_8);
1055 if (zoom_factor != 16)
1056 FreeBitmap(tmp_bitmap_16);
1058 if (zoom_factor != 32)
1059 FreeBitmap(tmp_bitmap_32);
1062 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1063 #if defined(TARGET_SDL)
1064 swap_bitmap.surface = old_bitmap->surface;
1065 old_bitmap->surface = new_bitmap->surface;
1066 new_bitmap->surface = swap_bitmap.surface;
1068 swap_bitmap.drawable = old_bitmap->drawable;
1069 old_bitmap->drawable = new_bitmap->drawable;
1070 new_bitmap->drawable = swap_bitmap.drawable;
1073 old_bitmap->width = new_bitmap->width;
1074 old_bitmap->height = new_bitmap->height;
1077 /* this replaces all blit masks created when loading -- maybe optimize this */
1079 #if defined(TARGET_X11)
1080 if (old_bitmap->clip_mask)
1081 XFreePixmap(display, old_bitmap->clip_mask);
1083 old_bitmap->clip_mask =
1084 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1086 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1088 SDL_Surface *old_surface = old_bitmap->surface;
1090 if (old_bitmap->surface_masked)
1091 SDL_FreeSurface(old_bitmap->surface_masked);
1093 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1094 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1095 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1096 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1097 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1102 UPDATE_BUSY_STATE();
1104 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1107 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1109 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1112 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1114 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1118 /* ------------------------------------------------------------------------- */
1119 /* mouse pointer functions */
1120 /* ------------------------------------------------------------------------- */
1122 #if !defined(PLATFORM_MSDOS)
1123 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1124 /* XPM image definitions */
1125 static const char *cursor_image_none[] =
1127 /* width height num_colors chars_per_pixel */
1156 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1157 static const char *cursor_image_dot[] =
1159 /* width height num_colors chars_per_pixel */
1188 static const char **cursor_image_playfield = cursor_image_dot;
1190 /* some people complained about a "white dot" on the screen and thought it
1191 was a graphical error... OK, let's just remove the whole pointer :-) */
1192 static const char **cursor_image_playfield = cursor_image_none;
1195 #if defined(TARGET_SDL)
1196 static const int cursor_bit_order = BIT_ORDER_MSB;
1197 #elif defined(TARGET_X11_NATIVE)
1198 static const int cursor_bit_order = BIT_ORDER_LSB;
1201 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1203 struct MouseCursorInfo *cursor;
1204 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1205 int header_lines = 4;
1208 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1210 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1213 for (y = 0; y < cursor->width; y++)
1215 for (x = 0; x < cursor->height; x++)
1218 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1223 cursor->data[i] = cursor->mask[i] = 0;
1226 switch (image[header_lines + y][x])
1229 cursor->data[i] |= bit_mask;
1230 cursor->mask[i] |= bit_mask;
1234 cursor->mask[i] |= bit_mask;
1243 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1247 #endif /* !PLATFORM_MSDOS */
1249 void SetMouseCursor(int mode)
1251 #if !defined(PLATFORM_MSDOS)
1252 static struct MouseCursorInfo *cursor_none = NULL;
1253 static struct MouseCursorInfo *cursor_playfield = NULL;
1254 struct MouseCursorInfo *cursor_new;
1256 if (cursor_none == NULL)
1257 cursor_none = get_cursor_from_image(cursor_image_none);
1259 if (cursor_playfield == NULL)
1260 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1262 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1263 mode == CURSOR_NONE ? cursor_none :
1264 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1266 #if defined(TARGET_SDL)
1267 SDLSetMouseCursor(cursor_new);
1268 #elif defined(TARGET_X11_NATIVE)
1269 X11SetMouseCursor(cursor_new);
1275 /* ========================================================================= */
1276 /* audio functions */
1277 /* ========================================================================= */
1279 void OpenAudio(void)
1281 /* always start with reliable default values */
1282 audio.sound_available = FALSE;
1283 audio.music_available = FALSE;
1284 audio.loops_available = FALSE;
1286 audio.sound_enabled = FALSE;
1287 audio.sound_deactivated = FALSE;
1289 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1290 audio.mixer_pid = 0;
1291 audio.device_name = NULL;
1292 audio.device_fd = -1;
1294 audio.num_channels = 0;
1295 audio.music_channel = 0;
1296 audio.first_sound_channel = 0;
1298 #if defined(TARGET_SDL)
1300 #elif defined(PLATFORM_UNIX)
1302 #elif defined(PLATFORM_MSDOS)
1307 void CloseAudio(void)
1309 #if defined(TARGET_SDL)
1311 #elif defined(PLATFORM_UNIX)
1313 #elif defined(PLATFORM_MSDOS)
1317 audio.sound_enabled = FALSE;
1320 void SetAudioMode(boolean enabled)
1322 if (!audio.sound_available)
1325 audio.sound_enabled = enabled;
1329 /* ========================================================================= */
1330 /* event functions */
1331 /* ========================================================================= */
1333 void InitEventFilter(EventFilter filter_function)
1335 #if defined(TARGET_SDL)
1336 /* set event filter to filter out certain events */
1337 SDL_SetEventFilter(filter_function);
1341 boolean PendingEvent(void)
1343 #if defined(TARGET_SDL)
1344 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1346 return (XPending(display) ? TRUE : FALSE);
1350 void NextEvent(Event *event)
1352 #if defined(TARGET_SDL)
1353 SDLNextEvent(event);
1355 XNextEvent(display, event);
1359 void PeekEvent(Event *event)
1361 #if defined(TARGET_SDL)
1362 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1364 XPeekEvent(display, event);
1368 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1370 #if defined(TARGET_SDL)
1373 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1374 (int)event->keysym.unicode,
1375 (int)event->keysym.sym,
1376 (int)SDL_GetModState());
1379 if (with_modifiers &&
1380 event->keysym.unicode > 0x0000 &&
1381 event->keysym.unicode < 0x2000)
1382 return event->keysym.unicode;
1384 return event->keysym.sym;
1389 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1390 (int)XLookupKeysym(event, event->state),
1391 (int)XLookupKeysym(event, 0));
1395 return XLookupKeysym(event, event->state);
1397 return XLookupKeysym(event, 0);
1401 KeyMod HandleKeyModState(Key key, int key_status)
1403 static KeyMod current_modifiers = KMOD_None;
1405 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1407 KeyMod new_modifier = KMOD_None;
1412 new_modifier = KMOD_Shift_L;
1415 new_modifier = KMOD_Shift_R;
1417 case KSYM_Control_L:
1418 new_modifier = KMOD_Control_L;
1420 case KSYM_Control_R:
1421 new_modifier = KMOD_Control_R;
1424 new_modifier = KMOD_Meta_L;
1427 new_modifier = KMOD_Meta_R;
1430 new_modifier = KMOD_Alt_L;
1433 new_modifier = KMOD_Alt_R;
1439 if (key_status == KEY_PRESSED)
1440 current_modifiers |= new_modifier;
1442 current_modifiers &= ~new_modifier;
1445 return current_modifiers;
1448 KeyMod GetKeyModState()
1450 #if defined(TARGET_SDL)
1451 return (KeyMod)SDL_GetModState();
1453 return HandleKeyModState(KSYM_UNDEFINED, 0);
1457 KeyMod GetKeyModStateFromEvents()
1459 /* always use key modifier state as tracked from key events (this is needed
1460 if the modifier key event was injected into the event queue, but the key
1461 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1462 query the keys as held pressed on the keyboard) -- this case is currently
1463 only used to filter out clipboard insert events from "True X-Mouse" tool */
1465 return HandleKeyModState(KSYM_UNDEFINED, 0);
1468 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1470 if (event->type != EVENT_CLIENTMESSAGE)
1473 #if defined(TARGET_SDL)
1474 return TRUE; /* the only possible message here is SDL_QUIT */
1475 #elif defined(PLATFORM_UNIX)
1476 if ((event->window == window->drawable) &&
1477 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1485 /* ========================================================================= */
1486 /* joystick functions */
1487 /* ========================================================================= */
1489 void InitJoysticks()
1493 #if defined(NO_JOYSTICK)
1494 return; /* joysticks generally deactivated by compile-time directive */
1497 /* always start with reliable default values */
1498 joystick.status = JOYSTICK_NOT_AVAILABLE;
1499 for (i = 0; i < MAX_PLAYERS; i++)
1500 joystick.fd[i] = -1; /* joystick device closed */
1502 #if defined(TARGET_SDL)
1504 #elif defined(PLATFORM_UNIX)
1505 UnixInitJoysticks();
1506 #elif defined(PLATFORM_MSDOS)
1507 MSDOSInitJoysticks();
1511 for (i = 0; i < MAX_PLAYERS; i++)
1512 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1516 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1518 #if defined(TARGET_SDL)
1519 return SDLReadJoystick(nr, x, y, b1, b2);
1520 #elif defined(PLATFORM_UNIX)
1521 return UnixReadJoystick(nr, x, y, b1, b2);
1522 #elif defined(PLATFORM_MSDOS)
1523 return MSDOSReadJoystick(nr, x, y, b1, b2);