1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
19 #if defined(PLATFORM_MSDOS)
31 /* ========================================================================= */
32 /* exported variables */
33 /* ========================================================================= */
35 struct ProgramInfo program;
36 struct OptionInfo options;
37 struct VideoSystemInfo video;
38 struct AudioSystemInfo audio;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
44 LevelDirTree *leveldir_first_all = NULL;
45 LevelDirTree *leveldir_first = NULL;
46 LevelDirTree *leveldir_current = NULL;
49 Display *display = NULL;
50 Visual *visual = NULL;
54 DrawWindow *window = NULL;
55 DrawBuffer *backbuffer = NULL;
56 DrawBuffer *drawto = NULL;
58 int button_status = MB_NOT_PRESSED;
59 boolean motion_status = FALSE;
61 int redraw_mask = REDRAW_NONE;
67 /* ========================================================================= */
68 /* init/close functions */
69 /* ========================================================================= */
71 void InitProgramInfo(char *argv0,
72 char *userdata_subdir, char *userdata_subdir_unix,
73 char *program_title, char *window_title, char *icon_title,
74 char *x11_icon_filename, char *x11_iconmask_filename,
75 char *sdl_icon_filename, char *msdos_cursor_filename,
76 char *cookie_prefix, char *filename_prefix,
79 program.command_basepath = getBasePath(argv0);
80 program.command_basename = getBaseName(argv0);
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_subdir_unix = userdata_subdir_unix;
84 program.userdata_path = getUserGameDataDir();
86 program.program_title = program_title;
87 program.window_title = window_title;
88 program.icon_title = icon_title;
90 program.x11_icon_filename = x11_icon_filename;
91 program.x11_iconmask_filename = x11_iconmask_filename;
92 program.sdl_icon_filename = sdl_icon_filename;
93 program.msdos_cursor_filename = msdos_cursor_filename;
95 program.cookie_prefix = cookie_prefix;
96 program.filename_prefix = filename_prefix;
98 program.version_major = VERSION_MAJOR(program_version);
99 program.version_minor = VERSION_MINOR(program_version);
100 program.version_patch = VERSION_PATCH(program_version);
102 program.error_filename = getErrorFilename(ERROR_BASENAME);
103 program.error_file = stderr;
106 void InitExitFunction(void (*exit_function)(int))
108 program.exit_function = exit_function;
110 /* set signal handlers to custom exit function */
111 signal(SIGINT, exit_function);
112 signal(SIGTERM, exit_function);
114 #if defined(TARGET_SDL)
115 /* set exit function to automatically cleanup SDL stuff after exit() */
120 void InitPlatformDependentStuff(void)
122 #if defined(PLATFORM_MSDOS)
126 #if defined(PLATFORM_MACOSX)
127 updateUserGameDataDir();
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
134 #if defined(TARGET_SDL)
135 if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
142 void ClosePlatformDependentStuff(void)
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
148 #if defined(PLATFORM_MSDOS)
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154 int real_sx, int real_sy,
155 int full_sxsize, int full_sysize,
156 Bitmap *field_save_buffer)
162 gfx.real_sx = real_sx;
163 gfx.real_sy = real_sy;
164 gfx.full_sxsize = full_sxsize;
165 gfx.full_sysize = full_sysize;
167 gfx.field_save_buffer = field_save_buffer;
170 gfx.background_bitmap = NULL;
171 gfx.background_bitmap_mask = REDRAW_NONE;
174 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
175 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
196 gfx.win_xsize = win_xsize;
197 gfx.win_ysize = win_ysize;
200 gfx.background_bitmap_mask = REDRAW_NONE;
202 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
208 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210 gfx.scrollbuffer_width = scrollbuffer_width;
211 gfx.scrollbuffer_height = scrollbuffer_height;
214 void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
216 gfx.clipping_enabled = enabled;
219 gfx.clip_width = width;
220 gfx.clip_height = height;
223 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
225 gfx.draw_busy_anim_function = draw_busy_anim_function;
228 void InitGfxCustomArtworkInfo()
230 gfx.override_level_graphics = FALSE;
231 gfx.override_level_sounds = FALSE;
232 gfx.override_level_music = FALSE;
234 gfx.draw_init_text = TRUE;
237 void SetDrawDeactivationMask(int draw_deactivation_mask)
239 gfx.draw_deactivation_mask = draw_deactivation_mask;
242 void SetDrawBackgroundMask(int draw_background_mask)
244 gfx.draw_background_mask = draw_background_mask;
247 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
248 int dest_x, int dest_y, int width, int height)
250 int bitmap_xsize = width;
251 int bitmap_ysize = height;
252 int tile_xsize = tile->width;
253 int tile_ysize = tile->height;
254 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
255 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
258 for (y = 0; y < tile_ysteps; y++)
260 for (x = 0; x < tile_xsteps; x++)
262 int draw_x = dest_x + x * tile_xsize;
263 int draw_y = dest_y + y * tile_ysize;
264 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
265 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
267 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
272 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
274 if (background_bitmap_tile != NULL)
275 gfx.background_bitmap_mask |= mask;
277 gfx.background_bitmap_mask &= ~mask;
280 if (gfx.background_bitmap == NULL)
281 gfx.background_bitmap = CreateBitmap(video.width, video.height,
285 if (background_bitmap_tile == NULL) /* empty background requested */
288 if (mask == REDRAW_ALL)
289 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
290 0, 0, video.width, video.height);
291 else if (mask == REDRAW_FIELD)
292 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
293 gfx.real_sx, gfx.real_sy,
294 gfx.full_sxsize, gfx.full_sysize);
295 else if (mask == REDRAW_DOOR_1)
297 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
299 gfx.dxsize, gfx.dysize);
303 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
305 /* remove every mask before setting mask for window */
306 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
307 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
308 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
311 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
313 /* remove window area mask before setting mask for main area */
314 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
315 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
316 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
319 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
321 /* remove window area mask before setting mask for door area */
322 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
323 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
324 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
328 /* ========================================================================= */
329 /* video functions */
330 /* ========================================================================= */
332 inline static int GetRealDepth(int depth)
334 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
337 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
338 int width, int height, Pixel color)
340 #if defined(TARGET_SDL)
341 SDLFillRectangle(bitmap, x, y, width, height, color);
343 X11FillRectangle(bitmap, x, y, width, height, color);
347 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
348 int src_x, int src_y, int width, int height,
349 int dst_x, int dst_y, int mask_mode)
351 #if defined(TARGET_SDL)
352 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
353 dst_x, dst_y, mask_mode);
355 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
356 dst_x, dst_y, mask_mode);
360 void InitVideoDisplay(void)
362 #if defined(TARGET_SDL)
363 SDLInitVideoDisplay();
365 X11InitVideoDisplay();
369 void CloseVideoDisplay(void)
371 KeyboardAutoRepeatOn();
373 #if defined(TARGET_SDL)
374 SDL_QuitSubSystem(SDL_INIT_VIDEO);
377 XCloseDisplay(display);
381 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
384 video.height = height;
385 video.depth = GetRealDepth(depth);
387 video.fullscreen_available = FULLSCREEN_STATUS;
388 video.fullscreen_enabled = FALSE;
390 video.fullscreen_mode_current = NULL;
391 video.fullscreen_modes = NULL;
394 #if defined(TARGET_SDL)
395 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
397 X11InitVideoBuffer(&backbuffer, &window);
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 Bitmap *CreateBitmapStruct(void)
441 #if defined(TARGET_SDL)
442 return checked_calloc(sizeof(struct SDLSurfaceInfo));
444 return checked_calloc(sizeof(struct X11DrawableInfo));
448 Bitmap *CreateBitmap(int width, int height, int depth)
450 Bitmap *new_bitmap = CreateBitmapStruct();
451 int real_width = MAX(1, width); /* prevent zero bitmap width */
452 int real_height = MAX(1, height); /* prevent zero bitmap height */
453 int real_depth = GetRealDepth(depth);
455 #if defined(TARGET_SDL)
456 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
458 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
461 new_bitmap->width = real_width;
462 new_bitmap->height = real_height;
467 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
469 Bitmap *new_bitmap = CreateBitmap(width, height, depth);
473 *bitmap = new_bitmap;
477 TransferBitmapPointers(new_bitmap, *bitmap);
482 void CloseWindow(DrawWindow *window)
484 #if defined(TARGET_X11)
485 X11CloseWindow(window);
489 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
492 if (draw_mask == REDRAW_NONE)
495 if (draw_mask & REDRAW_ALL)
498 if ((draw_mask & REDRAW_FIELD) &&
499 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
502 if ((draw_mask & REDRAW_DOOR_1) &&
503 x >= gfx.dx && y < gfx.dy + gfx.dysize)
506 if ((draw_mask & REDRAW_DOOR_2) &&
507 x >= gfx.dx && y >= gfx.vy)
513 boolean DrawingDeactivated(int x, int y, int width, int height)
515 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
518 boolean DrawingOnBackground(int x, int y)
520 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
521 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
524 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
525 int *width, int *height, boolean is_dest)
528 int clip_x, clip_y, clip_width, clip_height;
530 if (gfx.clipping_enabled && is_dest) /* only clip destination bitmap */
532 clip_x = MIN(MAX(0, gfx.clip_x), bitmap->width);
533 clip_y = MIN(MAX(0, gfx.clip_y), bitmap->height);
534 clip_width = MIN(MAX(0, gfx.clip_width), bitmap->width - clip_x);
535 clip_height = MIN(MAX(0, gfx.clip_height), bitmap->height - clip_y);
541 clip_width = bitmap->width;
542 clip_height = bitmap->height;
545 /* skip if rectangle completely outside bitmap */
547 if (*x + *width <= clip_x ||
548 *y + *height <= clip_y ||
549 *x >= clip_x + clip_width ||
550 *y >= clip_y + clip_height)
553 /* clip if rectangle overlaps bitmap */
557 *width -= clip_x - *x;
560 else if (*x + *width > clip_x + clip_width)
562 *width = clip_x + clip_width - *x;
567 *height -= clip_y - *y;
570 else if (*y + *height > clip_y + clip_height)
572 *height = clip_y + clip_height - *y;
579 /* skip if rectangle completely outside bitmap */
581 if (*x + *width <= 0 ||
583 *x >= bitmap->width ||
584 *y >= bitmap->height)
587 /* clip if rectangle overlaps bitmap */
594 else if (*x + *width > bitmap->width)
596 *width = bitmap->width - *x;
604 else if (*y + *height > bitmap->height)
606 *height = bitmap->height - *y;
613 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
614 int src_x, int src_y, int width, int height,
615 int dst_x, int dst_y)
617 int dst_x_unclipped = dst_x;
618 int dst_y_unclipped = dst_y;
620 if (DrawingDeactivated(dst_x, dst_y, width, height))
624 if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
625 !InClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height, TRUE))
628 /* source x/y might need adjustment if destination x/y was clipped top/left */
629 src_x += dst_x - dst_x_unclipped;
630 src_y += dst_y - dst_y_unclipped;
633 /* skip if rectangle starts outside bitmap */
634 if (src_x >= src_bitmap->width ||
635 src_y >= src_bitmap->height ||
636 dst_x >= dst_bitmap->width ||
637 dst_y >= dst_bitmap->height)
640 /* clip if rectangle overlaps bitmap */
641 if (src_x + width > src_bitmap->width)
642 width = src_bitmap->width - src_x;
643 if (src_y + height > src_bitmap->height)
644 height = src_bitmap->height - src_y;
645 if (dst_x + width > dst_bitmap->width)
646 width = dst_bitmap->width - dst_x;
647 if (dst_y + height > dst_bitmap->height)
648 height = dst_bitmap->height - dst_y;
652 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
653 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
654 but is already fixed in SVN and should therefore finally be fixed with
655 the next official SDL release, which is probably version 1.2.14.) */
657 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
658 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
659 if (src_bitmap == dst_bitmap)
661 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
663 /* needed when blitting directly to same bitmap -- should not be needed with
664 recent SDL libraries, but apparently does not work in 1.2.11 directly */
666 static Bitmap *tmp_bitmap = NULL;
667 static int tmp_bitmap_xsize = 0;
668 static int tmp_bitmap_ysize = 0;
670 /* start with largest static bitmaps for initial bitmap size ... */
671 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
673 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
674 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
677 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
678 if (src_bitmap->width > tmp_bitmap_xsize ||
679 src_bitmap->height > tmp_bitmap_ysize)
681 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
682 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
684 FreeBitmap(tmp_bitmap);
689 if (tmp_bitmap == NULL)
690 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
693 sysCopyArea(src_bitmap, tmp_bitmap,
694 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
695 sysCopyArea(tmp_bitmap, dst_bitmap,
696 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
704 sysCopyArea(src_bitmap, dst_bitmap,
705 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
708 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
709 int fade_mode, int fade_delay, int post_delay,
710 void (*draw_border_function)(void))
713 /* (use destination bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
714 if (!InClippedRectangle(backbuffer, &x, &y, &width, &height, TRUE))
718 #if defined(TARGET_SDL)
719 SDLFadeRectangle(bitmap_cross, x, y, width, height,
720 fade_mode, fade_delay, post_delay, draw_border_function);
722 X11FadeRectangle(bitmap_cross, x, y, width, height,
723 fade_mode, fade_delay, post_delay, draw_border_function);
727 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
730 if (DrawingDeactivated(x, y, width, height))
734 if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
737 /* skip if rectangle starts outside bitmap */
738 if (x >= bitmap->width ||
742 /* clip if rectangle overlaps bitmap */
743 if (x + width > bitmap->width)
744 width = bitmap->width - x;
745 if (y + height > bitmap->height)
746 height = bitmap->height - y;
749 sysFillRectangle(bitmap, x, y, width, height, color);
752 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
754 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
757 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
758 int width, int height)
760 if (DrawingOnBackground(x, y))
761 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
763 ClearRectangle(bitmap, x, y, width, height);
766 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
768 #if defined(TARGET_X11)
771 bitmap->clip_gc = clip_gc;
772 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
777 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
779 #if defined(TARGET_X11)
782 bitmap->clip_gc = clip_gc;
783 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
788 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
789 int src_x, int src_y, int width, int height,
790 int dst_x, int dst_y)
792 if (DrawingDeactivated(dst_x, dst_y, width, height))
795 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
796 dst_x, dst_y, BLIT_MASKED);
799 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
800 int src_x, int src_y, int width, int height,
801 int dst_x, int dst_y)
803 if (DrawingOnBackground(dst_x, dst_y))
805 /* draw background */
806 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
809 /* draw foreground */
810 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
811 dst_x - src_x, dst_y - src_y);
812 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
816 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
820 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
823 #if defined(TARGET_SDL)
824 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
826 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
830 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
833 #if defined(TARGET_SDL)
834 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
836 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
840 #if !defined(TARGET_X11_NATIVE)
841 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
842 int to_x, int to_y, Pixel pixel, int line_width)
846 for (x = 0; x < line_width; x++)
848 for (y = 0; y < line_width; y++)
850 int dx = x - line_width / 2;
851 int dy = y - line_width / 2;
853 if ((x == 0 && y == 0) ||
854 (x == 0 && y == line_width - 1) ||
855 (x == line_width - 1 && y == 0) ||
856 (x == line_width - 1 && y == line_width - 1))
859 #if defined(TARGET_SDL)
861 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
862 #elif defined(TARGET_ALLEGRO)
863 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
864 to_x + dx, to_y + dy, pixel);
871 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
873 #if !defined(TARGET_X11_NATIVE)
877 for (i = 0; i < num_points - 1; i++)
878 DrawLine(bitmap, points[i].x, points[i].y,
879 points[i + 1].x, points[i + 1].y, pixel, line_width);
882 SDLDrawLines(bitmap->surface, points, num_points, pixel);
885 XSetForeground(display, bitmap->line_gc[1], pixel);
886 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
887 (XPoint *)points, num_points, CoordModeOrigin);
891 Pixel GetPixel(Bitmap *bitmap, int x, int y)
893 if (x < 0 || x >= bitmap->width ||
894 y < 0 || y >= bitmap->height)
897 #if defined(TARGET_SDL)
898 return SDLGetPixel(bitmap, x, y);
899 #elif defined(TARGET_ALLEGRO)
900 return AllegroGetPixel(bitmap->drawable, x, y);
902 return X11GetPixel(bitmap, x, y);
906 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
907 unsigned int color_g, unsigned int color_b)
909 #if defined(TARGET_SDL)
910 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
911 #elif defined(TARGET_ALLEGRO)
912 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
914 return X11GetPixelFromRGB(color_r, color_g, color_b);
918 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
920 unsigned int color_r = (color >> 16) & 0xff;
921 unsigned int color_g = (color >> 8) & 0xff;
922 unsigned int color_b = (color >> 0) & 0xff;
924 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
927 /* execute all pending screen drawing operations */
928 void FlushDisplay(void)
935 /* execute and wait for all pending screen drawing operations */
936 void SyncDisplay(void)
939 XSync(display, FALSE);
943 void KeyboardAutoRepeatOn(void)
945 #if defined(TARGET_SDL)
946 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
947 SDL_DEFAULT_REPEAT_INTERVAL / 2);
948 SDL_EnableUNICODE(1);
951 XAutoRepeatOn(display);
955 void KeyboardAutoRepeatOff(void)
957 #if defined(TARGET_SDL)
958 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
959 SDL_EnableUNICODE(0);
962 XAutoRepeatOff(display);
966 boolean PointerInWindow(DrawWindow *window)
968 #if defined(TARGET_SDL)
976 /* if XQueryPointer() returns False, the pointer
977 is not on the same screen as the specified window */
978 return XQueryPointer(display, window->drawable, &root, &child,
979 &root_x, &root_y, &win_x, &win_y, &mask);
983 boolean SetVideoMode(boolean fullscreen)
985 #if defined(TARGET_SDL)
986 return SDLSetVideoMode(&backbuffer, fullscreen);
988 boolean success = TRUE;
990 if (fullscreen && video.fullscreen_available)
992 Error(ERR_WARN, "fullscreen not available in X11 version");
994 /* display error message only once */
995 video.fullscreen_available = FALSE;
1004 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
1006 #if defined(TARGET_SDL)
1007 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
1008 (!fullscreen && video.fullscreen_enabled))
1009 fullscreen = SetVideoMode(fullscreen);
1015 Bitmap *LoadImage(char *filename)
1019 #if defined(TARGET_SDL)
1020 new_bitmap = SDLLoadImage(filename);
1022 new_bitmap = X11LoadImage(filename);
1026 new_bitmap->source_filename = getStringCopy(filename);
1031 Bitmap *LoadCustomImage(char *basename)
1033 char *filename = getCustomImageFilename(basename);
1036 if (filename == NULL)
1037 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
1039 if ((new_bitmap = LoadImage(filename)) == NULL)
1040 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
1045 void ReloadCustomImage(Bitmap *bitmap, char *basename)
1047 char *filename = getCustomImageFilename(basename);
1050 if (filename == NULL) /* (should never happen) */
1052 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
1056 if (strEqual(filename, bitmap->source_filename))
1058 /* The old and new image are the same (have the same filename and path).
1059 This usually means that this image does not exist in this graphic set
1060 and a fallback to the existing image is done. */
1065 if ((new_bitmap = LoadImage(filename)) == NULL)
1067 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1071 if (bitmap->width != new_bitmap->width ||
1072 bitmap->height != new_bitmap->height)
1074 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1076 FreeBitmap(new_bitmap);
1080 TransferBitmapPointers(new_bitmap, bitmap);
1084 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1086 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1088 #if defined(TARGET_SDL)
1089 SDLZoomBitmap(src_bitmap, dst_bitmap);
1091 X11ZoomBitmap(src_bitmap, dst_bitmap);
1097 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1098 boolean create_small_bitmaps)
1102 Bitmap *tmp_bitmap_1;
1103 Bitmap *tmp_bitmap_2;
1104 Bitmap *tmp_bitmap_4;
1105 Bitmap *tmp_bitmap_8;
1106 Bitmap *tmp_bitmap_16;
1107 Bitmap *tmp_bitmap_32;
1108 int width_1, height_1;
1109 int width_2, height_2;
1110 int width_4, height_4;
1111 int width_8, height_8;
1112 int width_16, height_16;
1113 int width_32, height_32;
1114 int new_width, new_height;
1116 /* calculate new image dimensions for normal sized image */
1117 width_1 = old_bitmap->width * zoom_factor;
1118 height_1 = old_bitmap->height * zoom_factor;
1120 /* get image with normal size (this might require scaling up) */
1121 if (zoom_factor != 1)
1122 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1124 tmp_bitmap_1 = old_bitmap;
1126 /* this is only needed to make compilers happy */
1127 tmp_bitmap_2 = NULL;
1128 tmp_bitmap_4 = NULL;
1129 tmp_bitmap_8 = NULL;
1130 tmp_bitmap_16 = NULL;
1131 tmp_bitmap_32 = NULL;
1133 if (create_small_bitmaps)
1135 /* calculate new image dimensions for small images */
1136 width_2 = width_1 / 2;
1137 height_2 = height_1 / 2;
1138 width_4 = width_1 / 4;
1139 height_4 = height_1 / 4;
1140 width_8 = width_1 / 8;
1141 height_8 = height_1 / 8;
1142 width_16 = width_1 / 16;
1143 height_16 = height_1 / 16;
1144 width_32 = width_1 / 32;
1145 height_32 = height_1 / 32;
1147 UPDATE_BUSY_STATE();
1149 /* get image with 1/2 of normal size (for use in the level editor) */
1150 if (zoom_factor != 2)
1151 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1153 tmp_bitmap_2 = old_bitmap;
1155 UPDATE_BUSY_STATE();
1157 /* get image with 1/4 of normal size (for use in the level editor) */
1158 if (zoom_factor != 4)
1159 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1161 tmp_bitmap_4 = old_bitmap;
1163 UPDATE_BUSY_STATE();
1165 /* get image with 1/8 of normal size (for use on the preview screen) */
1166 if (zoom_factor != 8)
1167 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1169 tmp_bitmap_8 = old_bitmap;
1171 UPDATE_BUSY_STATE();
1173 /* get image with 1/16 of normal size (for use on the preview screen) */
1174 if (zoom_factor != 16)
1175 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1177 tmp_bitmap_16 = old_bitmap;
1179 UPDATE_BUSY_STATE();
1181 /* get image with 1/32 of normal size (for use on the preview screen) */
1182 if (zoom_factor != 32)
1183 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1185 tmp_bitmap_32 = old_bitmap;
1187 UPDATE_BUSY_STATE();
1191 /* if image was scaled up, create new clipmask for normal size image */
1192 if (zoom_factor != 1)
1194 #if defined(TARGET_X11)
1195 if (old_bitmap->clip_mask)
1196 XFreePixmap(display, old_bitmap->clip_mask);
1198 old_bitmap->clip_mask =
1199 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1201 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1203 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1205 if (old_bitmap->surface_masked)
1206 SDL_FreeSurface(old_bitmap->surface_masked);
1208 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1209 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1210 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1211 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1212 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1217 if (create_small_bitmaps)
1219 new_width = width_1;
1220 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1222 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1224 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1225 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1227 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1228 width_1 / 2, height_1);
1229 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1230 3 * width_1 / 4, height_1);
1231 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1232 7 * width_1 / 8, height_1);
1233 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1234 15 * width_1 / 16, height_1);
1236 UPDATE_BUSY_STATE();
1240 new_width = width_1;
1241 new_height = height_1;
1243 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1246 if (create_small_bitmaps)
1248 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1249 if (zoom_factor != 1)
1250 FreeBitmap(tmp_bitmap_1);
1252 if (zoom_factor != 2)
1253 FreeBitmap(tmp_bitmap_2);
1255 if (zoom_factor != 4)
1256 FreeBitmap(tmp_bitmap_4);
1258 if (zoom_factor != 8)
1259 FreeBitmap(tmp_bitmap_8);
1261 if (zoom_factor != 16)
1262 FreeBitmap(tmp_bitmap_16);
1264 if (zoom_factor != 32)
1265 FreeBitmap(tmp_bitmap_32);
1268 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1269 #if defined(TARGET_SDL)
1270 swap_bitmap.surface = old_bitmap->surface;
1271 old_bitmap->surface = new_bitmap->surface;
1272 new_bitmap->surface = swap_bitmap.surface;
1274 swap_bitmap.drawable = old_bitmap->drawable;
1275 old_bitmap->drawable = new_bitmap->drawable;
1276 new_bitmap->drawable = swap_bitmap.drawable;
1279 old_bitmap->width = new_bitmap->width;
1280 old_bitmap->height = new_bitmap->height;
1283 /* this replaces all blit masks created when loading -- maybe optimize this */
1285 #if defined(TARGET_X11)
1286 if (old_bitmap->clip_mask)
1287 XFreePixmap(display, old_bitmap->clip_mask);
1289 old_bitmap->clip_mask =
1290 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1292 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1294 SDL_Surface *old_surface = old_bitmap->surface;
1296 if (old_bitmap->surface_masked)
1297 SDL_FreeSurface(old_bitmap->surface_masked);
1299 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1300 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1301 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1302 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1303 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1308 UPDATE_BUSY_STATE();
1310 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1313 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1315 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1318 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1320 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1324 /* ------------------------------------------------------------------------- */
1325 /* mouse pointer functions */
1326 /* ------------------------------------------------------------------------- */
1328 #if !defined(PLATFORM_MSDOS)
1329 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1330 /* XPM image definitions */
1331 static const char *cursor_image_none[] =
1333 /* width height num_colors chars_per_pixel */
1362 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1363 static const char *cursor_image_dot[] =
1365 /* width height num_colors chars_per_pixel */
1394 static const char **cursor_image_playfield = cursor_image_dot;
1396 /* some people complained about a "white dot" on the screen and thought it
1397 was a graphical error... OK, let's just remove the whole pointer :-) */
1398 static const char **cursor_image_playfield = cursor_image_none;
1401 #if defined(TARGET_SDL)
1402 static const int cursor_bit_order = BIT_ORDER_MSB;
1403 #elif defined(TARGET_X11_NATIVE)
1404 static const int cursor_bit_order = BIT_ORDER_LSB;
1407 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1409 struct MouseCursorInfo *cursor;
1410 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1411 int header_lines = 4;
1414 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1416 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1419 for (y = 0; y < cursor->width; y++)
1421 for (x = 0; x < cursor->height; x++)
1424 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1429 cursor->data[i] = cursor->mask[i] = 0;
1432 switch (image[header_lines + y][x])
1435 cursor->data[i] |= bit_mask;
1436 cursor->mask[i] |= bit_mask;
1440 cursor->mask[i] |= bit_mask;
1449 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1453 #endif /* !PLATFORM_MSDOS */
1455 void SetMouseCursor(int mode)
1457 #if !defined(PLATFORM_MSDOS)
1458 static struct MouseCursorInfo *cursor_none = NULL;
1459 static struct MouseCursorInfo *cursor_playfield = NULL;
1460 struct MouseCursorInfo *cursor_new;
1462 if (cursor_none == NULL)
1463 cursor_none = get_cursor_from_image(cursor_image_none);
1465 if (cursor_playfield == NULL)
1466 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1468 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1469 mode == CURSOR_NONE ? cursor_none :
1470 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1472 #if defined(TARGET_SDL)
1473 SDLSetMouseCursor(cursor_new);
1474 #elif defined(TARGET_X11_NATIVE)
1475 X11SetMouseCursor(cursor_new);
1481 /* ========================================================================= */
1482 /* audio functions */
1483 /* ========================================================================= */
1485 void OpenAudio(void)
1487 /* always start with reliable default values */
1488 audio.sound_available = FALSE;
1489 audio.music_available = FALSE;
1490 audio.loops_available = FALSE;
1492 audio.sound_enabled = FALSE;
1493 audio.sound_deactivated = FALSE;
1495 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1496 audio.mixer_pid = 0;
1497 audio.device_name = NULL;
1498 audio.device_fd = -1;
1500 audio.num_channels = 0;
1501 audio.music_channel = 0;
1502 audio.first_sound_channel = 0;
1504 #if defined(TARGET_SDL)
1506 #elif defined(PLATFORM_UNIX)
1508 #elif defined(PLATFORM_MSDOS)
1513 void CloseAudio(void)
1515 #if defined(TARGET_SDL)
1517 #elif defined(PLATFORM_UNIX)
1519 #elif defined(PLATFORM_MSDOS)
1523 audio.sound_enabled = FALSE;
1526 void SetAudioMode(boolean enabled)
1528 if (!audio.sound_available)
1531 audio.sound_enabled = enabled;
1535 /* ========================================================================= */
1536 /* event functions */
1537 /* ========================================================================= */
1539 void InitEventFilter(EventFilter filter_function)
1541 #if defined(TARGET_SDL)
1542 /* set event filter to filter out certain events */
1543 SDL_SetEventFilter(filter_function);
1547 boolean PendingEvent(void)
1549 #if defined(TARGET_SDL)
1550 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1552 return (XPending(display) ? TRUE : FALSE);
1556 void NextEvent(Event *event)
1558 #if defined(TARGET_SDL)
1559 SDLNextEvent(event);
1561 XNextEvent(display, event);
1565 void PeekEvent(Event *event)
1567 #if defined(TARGET_SDL)
1568 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1570 XPeekEvent(display, event);
1574 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1576 #if defined(TARGET_SDL)
1579 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1580 (int)event->keysym.unicode,
1581 (int)event->keysym.sym,
1582 (int)SDL_GetModState());
1585 if (with_modifiers &&
1586 event->keysym.unicode > 0x0000 &&
1587 event->keysym.unicode < 0x2000)
1588 return event->keysym.unicode;
1590 return event->keysym.sym;
1595 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1596 (int)XLookupKeysym(event, event->state),
1597 (int)XLookupKeysym(event, 0));
1601 return XLookupKeysym(event, event->state);
1603 return XLookupKeysym(event, 0);
1607 KeyMod HandleKeyModState(Key key, int key_status)
1609 static KeyMod current_modifiers = KMOD_None;
1611 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1613 KeyMod new_modifier = KMOD_None;
1618 new_modifier = KMOD_Shift_L;
1621 new_modifier = KMOD_Shift_R;
1623 case KSYM_Control_L:
1624 new_modifier = KMOD_Control_L;
1626 case KSYM_Control_R:
1627 new_modifier = KMOD_Control_R;
1630 new_modifier = KMOD_Meta_L;
1633 new_modifier = KMOD_Meta_R;
1636 new_modifier = KMOD_Alt_L;
1639 new_modifier = KMOD_Alt_R;
1645 if (key_status == KEY_PRESSED)
1646 current_modifiers |= new_modifier;
1648 current_modifiers &= ~new_modifier;
1651 return current_modifiers;
1654 KeyMod GetKeyModState()
1656 #if defined(TARGET_SDL)
1657 return (KeyMod)SDL_GetModState();
1659 return HandleKeyModState(KSYM_UNDEFINED, 0);
1663 KeyMod GetKeyModStateFromEvents()
1665 /* always use key modifier state as tracked from key events (this is needed
1666 if the modifier key event was injected into the event queue, but the key
1667 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1668 query the keys as held pressed on the keyboard) -- this case is currently
1669 only used to filter out clipboard insert events from "True X-Mouse" tool */
1671 return HandleKeyModState(KSYM_UNDEFINED, 0);
1674 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1676 if (event->type != EVENT_CLIENTMESSAGE)
1679 #if defined(TARGET_SDL)
1680 return TRUE; /* the only possible message here is SDL_QUIT */
1681 #elif defined(PLATFORM_UNIX)
1682 if ((event->window == window->drawable) &&
1683 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1691 /* ========================================================================= */
1692 /* joystick functions */
1693 /* ========================================================================= */
1695 void InitJoysticks()
1699 #if defined(NO_JOYSTICK)
1700 return; /* joysticks generally deactivated by compile-time directive */
1703 /* always start with reliable default values */
1704 joystick.status = JOYSTICK_NOT_AVAILABLE;
1705 for (i = 0; i < MAX_PLAYERS; i++)
1706 joystick.fd[i] = -1; /* joystick device closed */
1708 #if defined(TARGET_SDL)
1710 #elif defined(PLATFORM_UNIX)
1711 UnixInitJoysticks();
1712 #elif defined(PLATFORM_MSDOS)
1713 MSDOSInitJoysticks();
1717 for (i = 0; i < MAX_PLAYERS; i++)
1718 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1722 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1724 #if defined(TARGET_SDL)
1725 return SDLReadJoystick(nr, x, y, b1, b2);
1726 #elif defined(PLATFORM_UNIX)
1727 return UnixReadJoystick(nr, x, y, b1, b2);
1728 #elif defined(PLATFORM_MSDOS)
1729 return MSDOSReadJoystick(nr, x, y, b1, b2);