1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
19 #if defined(PLATFORM_MSDOS)
31 /* ========================================================================= */
32 /* exported variables */
33 /* ========================================================================= */
35 struct ProgramInfo program;
36 struct OptionInfo options;
37 struct VideoSystemInfo video;
38 struct AudioSystemInfo audio;
40 struct ArtworkInfo artwork;
41 struct JoystickInfo joystick;
42 struct SetupInfo setup;
44 LevelDirTree *leveldir_first_all = NULL;
45 LevelDirTree *leveldir_first = NULL;
46 LevelDirTree *leveldir_current = NULL;
49 Display *display = NULL;
50 Visual *visual = NULL;
54 DrawWindow *window = NULL;
55 DrawBuffer *backbuffer = NULL;
56 DrawBuffer *drawto = NULL;
58 int button_status = MB_NOT_PRESSED;
59 boolean motion_status = FALSE;
61 int redraw_mask = REDRAW_NONE;
67 /* ========================================================================= */
68 /* init/close functions */
69 /* ========================================================================= */
71 void InitProgramInfo(char *argv0,
72 char *userdata_subdir, char *userdata_subdir_unix,
73 char *program_title, char *window_title, char *icon_title,
74 char *x11_icon_filename, char *x11_iconmask_filename,
75 char *sdl_icon_filename, char *msdos_cursor_filename,
76 char *cookie_prefix, char *filename_prefix,
79 program.command_basepath = getBasePath(argv0);
80 program.command_basename = getBaseName(argv0);
82 program.userdata_subdir = userdata_subdir;
83 program.userdata_subdir_unix = userdata_subdir_unix;
84 program.userdata_path = getUserGameDataDir();
86 program.program_title = program_title;
87 program.window_title = window_title;
88 program.icon_title = icon_title;
90 program.x11_icon_filename = x11_icon_filename;
91 program.x11_iconmask_filename = x11_iconmask_filename;
92 program.sdl_icon_filename = sdl_icon_filename;
93 program.msdos_cursor_filename = msdos_cursor_filename;
95 program.cookie_prefix = cookie_prefix;
96 program.filename_prefix = filename_prefix;
98 program.version_major = VERSION_MAJOR(program_version);
99 program.version_minor = VERSION_MINOR(program_version);
100 program.version_patch = VERSION_PATCH(program_version);
102 program.error_filename = getErrorFilename(ERROR_BASENAME);
103 program.error_file = stderr;
106 void InitExitFunction(void (*exit_function)(int))
108 program.exit_function = exit_function;
110 /* set signal handlers to custom exit function */
111 signal(SIGINT, exit_function);
112 signal(SIGTERM, exit_function);
114 #if defined(TARGET_SDL)
115 /* set exit function to automatically cleanup SDL stuff after exit() */
120 void InitPlatformDependentStuff(void)
122 #if defined(PLATFORM_MSDOS)
126 #if defined(PLATFORM_MACOSX)
127 updateUserGameDataDir();
130 #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX)
134 #if defined(TARGET_SDL)
135 if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
136 Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
142 void ClosePlatformDependentStuff(void)
144 #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS)
148 #if defined(PLATFORM_MSDOS)
153 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
154 int real_sx, int real_sy,
155 int full_sxsize, int full_sysize,
156 Bitmap *field_save_buffer)
162 gfx.real_sx = real_sx;
163 gfx.real_sy = real_sy;
164 gfx.full_sxsize = full_sxsize;
165 gfx.full_sysize = full_sysize;
167 gfx.field_save_buffer = field_save_buffer;
170 gfx.background_bitmap = NULL;
171 gfx.background_bitmap_mask = REDRAW_NONE;
174 SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */
175 SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */
178 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
186 void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize)
194 void InitGfxWindowInfo(int win_xsize, int win_ysize)
196 gfx.win_xsize = win_xsize;
197 gfx.win_ysize = win_ysize;
200 gfx.background_bitmap_mask = REDRAW_NONE;
202 ReCreateBitmap(&gfx.background_bitmap, win_xsize, win_ysize, DEFAULT_DEPTH);
206 void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height)
208 /* currently only used by MSDOS code to alloc VRAM buffer, if available */
209 /* 2009-03-24: also (temporarily?) used for overlapping blit workaround */
210 gfx.scrollbuffer_width = scrollbuffer_width;
211 gfx.scrollbuffer_height = scrollbuffer_height;
214 void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
216 gfx.draw_busy_anim_function = draw_busy_anim_function;
219 void InitGfxCustomArtworkInfo()
221 gfx.override_level_graphics = FALSE;
222 gfx.override_level_sounds = FALSE;
223 gfx.override_level_music = FALSE;
225 gfx.draw_init_text = TRUE;
228 void SetDrawDeactivationMask(int draw_deactivation_mask)
230 gfx.draw_deactivation_mask = draw_deactivation_mask;
233 void SetDrawBackgroundMask(int draw_background_mask)
235 gfx.draw_background_mask = draw_background_mask;
238 static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
239 int dest_x, int dest_y, int width, int height)
241 int bitmap_xsize = width;
242 int bitmap_ysize = height;
243 int tile_xsize = tile->width;
244 int tile_ysize = tile->height;
245 int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
246 int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
249 for (y = 0; y < tile_ysteps; y++)
251 for (x = 0; x < tile_xsteps; x++)
253 int draw_x = dest_x + x * tile_xsize;
254 int draw_y = dest_y + y * tile_ysize;
255 int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
256 int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
258 BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
263 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
265 if (background_bitmap_tile != NULL)
266 gfx.background_bitmap_mask |= mask;
268 gfx.background_bitmap_mask &= ~mask;
271 if (gfx.background_bitmap == NULL)
272 gfx.background_bitmap = CreateBitmap(video.width, video.height,
276 if (background_bitmap_tile == NULL) /* empty background requested */
279 if (mask == REDRAW_ALL)
280 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
281 0, 0, video.width, video.height);
282 else if (mask == REDRAW_FIELD)
283 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
284 gfx.real_sx, gfx.real_sy,
285 gfx.full_sxsize, gfx.full_sysize);
286 else if (mask == REDRAW_DOOR_1)
288 DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
290 gfx.dxsize, gfx.dysize);
294 void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
296 /* remove every mask before setting mask for window */
297 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
298 SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */
299 SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
302 void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
304 /* remove window area mask before setting mask for main area */
305 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
306 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
307 SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
310 void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
312 /* remove window area mask before setting mask for door area */
313 /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */
314 SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */
315 SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
319 /* ========================================================================= */
320 /* video functions */
321 /* ========================================================================= */
323 inline static int GetRealDepth(int depth)
325 return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
328 inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
329 int width, int height, Pixel color)
331 #if defined(TARGET_SDL)
332 SDLFillRectangle(bitmap, x, y, width, height, color);
334 X11FillRectangle(bitmap, x, y, width, height, color);
338 inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
339 int src_x, int src_y, int width, int height,
340 int dst_x, int dst_y, int mask_mode)
342 #if defined(TARGET_SDL)
343 SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
344 dst_x, dst_y, mask_mode);
346 X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
347 dst_x, dst_y, mask_mode);
351 void InitVideoDisplay(void)
353 #if defined(TARGET_SDL)
354 SDLInitVideoDisplay();
356 X11InitVideoDisplay();
360 void CloseVideoDisplay(void)
362 KeyboardAutoRepeatOn();
364 #if defined(TARGET_SDL)
365 SDL_QuitSubSystem(SDL_INIT_VIDEO);
368 XCloseDisplay(display);
372 void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
375 video.height = height;
376 video.depth = GetRealDepth(depth);
378 video.fullscreen_available = FULLSCREEN_STATUS;
379 video.fullscreen_enabled = FALSE;
381 video.fullscreen_mode_current = NULL;
382 video.fullscreen_modes = NULL;
385 #if defined(TARGET_SDL)
386 SDLInitVideoBuffer(&backbuffer, &window, fullscreen);
388 X11InitVideoBuffer(&backbuffer, &window);
394 inline static void FreeBitmapPointers(Bitmap *bitmap)
399 #if defined(TARGET_SDL)
400 SDLFreeBitmapPointers(bitmap);
402 X11FreeBitmapPointers(bitmap);
405 checked_free(bitmap->source_filename);
406 bitmap->source_filename = NULL;
409 inline static void TransferBitmapPointers(Bitmap *src_bitmap,
412 if (src_bitmap == NULL || dst_bitmap == NULL)
415 FreeBitmapPointers(dst_bitmap);
417 *dst_bitmap = *src_bitmap;
420 void FreeBitmap(Bitmap *bitmap)
425 FreeBitmapPointers(bitmap);
430 Bitmap *CreateBitmapStruct(void)
432 #if defined(TARGET_SDL)
433 return checked_calloc(sizeof(struct SDLSurfaceInfo));
435 return checked_calloc(sizeof(struct X11DrawableInfo));
439 Bitmap *CreateBitmap(int width, int height, int depth)
441 Bitmap *new_bitmap = CreateBitmapStruct();
442 int real_width = MAX(1, width); /* prevent zero bitmap width */
443 int real_height = MAX(1, height); /* prevent zero bitmap height */
444 int real_depth = GetRealDepth(depth);
446 #if defined(TARGET_SDL)
447 SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
449 X11CreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
452 new_bitmap->width = real_width;
453 new_bitmap->height = real_height;
458 void ReCreateBitmap(Bitmap **bitmap, int width, int height, int depth)
460 Bitmap *new_bitmap = CreateBitmap(width, height, depth);
464 *bitmap = new_bitmap;
468 TransferBitmapPointers(new_bitmap, *bitmap);
473 void CloseWindow(DrawWindow *window)
475 #if defined(TARGET_X11)
476 X11CloseWindow(window);
480 inline static boolean CheckDrawingArea(int x, int y, int width, int height,
483 if (draw_mask == REDRAW_NONE)
486 if (draw_mask & REDRAW_ALL)
489 if ((draw_mask & REDRAW_FIELD) &&
490 x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize)
493 if ((draw_mask & REDRAW_DOOR_1) &&
494 x >= gfx.dx && y < gfx.dy + gfx.dysize)
497 if ((draw_mask & REDRAW_DOOR_2) &&
498 x >= gfx.dx && y >= gfx.vy)
504 boolean DrawingDeactivated(int x, int y, int width, int height)
506 return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
509 boolean DrawingOnBackground(int x, int y)
511 return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
512 CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
515 static boolean ValidClippedRectangle(Bitmap *bitmap, int *x, int *y,
516 int *width, int *height)
518 /* skip if rectangle completely outside bitmap */
520 if (*x + *width <= 0 ||
522 *x >= bitmap->width ||
523 *y >= bitmap->height)
526 /* clip if rectangle overlaps bitmap */
533 else if (*x + *width > bitmap->width)
534 *width = bitmap->width - *x;
541 else if (*y + *height > bitmap->height)
542 *height = bitmap->height - *y;
547 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
548 int src_x, int src_y, int width, int height,
549 int dst_x, int dst_y)
551 if (DrawingDeactivated(dst_x, dst_y, width, height))
555 if (!ValidClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height) ||
556 !ValidClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height))
559 /* skip if rectangle starts outside bitmap */
560 if (src_x >= src_bitmap->width ||
561 src_y >= src_bitmap->height ||
562 dst_x >= dst_bitmap->width ||
563 dst_y >= dst_bitmap->height)
566 /* clip if rectangle overlaps bitmap */
567 if (src_x + width > src_bitmap->width)
568 width = src_bitmap->width - src_x;
569 if (src_y + height > src_bitmap->height)
570 height = src_bitmap->height - src_y;
571 if (dst_x + width > dst_bitmap->width)
572 width = dst_bitmap->width - dst_x;
573 if (dst_y + height > dst_bitmap->height)
574 height = dst_bitmap->height - dst_y;
578 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
579 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
580 but is already fixed in SVN and should therefore finally be fixed with
581 the next official SDL release, which is probably version 1.2.14.) */
583 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
584 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
585 if (src_bitmap == dst_bitmap)
587 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
589 /* needed when blitting directly to same bitmap -- should not be needed with
590 recent SDL libraries, but apparently does not work in 1.2.11 directly */
592 static Bitmap *tmp_bitmap = NULL;
593 static int tmp_bitmap_xsize = 0;
594 static int tmp_bitmap_ysize = 0;
596 /* start with largest static bitmaps for initial bitmap size ... */
597 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
599 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
600 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
603 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
604 if (src_bitmap->width > tmp_bitmap_xsize ||
605 src_bitmap->height > tmp_bitmap_ysize)
607 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
608 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
610 FreeBitmap(tmp_bitmap);
615 if (tmp_bitmap == NULL)
616 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
619 sysCopyArea(src_bitmap, tmp_bitmap,
620 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
621 sysCopyArea(tmp_bitmap, dst_bitmap,
622 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
630 sysCopyArea(src_bitmap, dst_bitmap,
631 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
634 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
635 int fade_mode, int fade_delay, int post_delay,
636 void (*draw_border_function)(void))
639 /* (use bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
640 if (!ValidClippedRectangle(backbuffer, &x, &y, &width, &height))
644 #if defined(TARGET_SDL)
645 SDLFadeRectangle(bitmap_cross, x, y, width, height,
646 fade_mode, fade_delay, post_delay, draw_border_function);
648 X11FadeRectangle(bitmap_cross, x, y, width, height,
649 fade_mode, fade_delay, post_delay, draw_border_function);
653 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
656 if (DrawingDeactivated(x, y, width, height))
660 if (!ValidClippedRectangle(bitmap, &x, &y, &width, &height))
663 /* skip if rectangle starts outside bitmap */
664 if (x >= bitmap->width ||
668 /* clip if rectangle overlaps bitmap */
669 if (x + width > bitmap->width)
670 width = bitmap->width - x;
671 if (y + height > bitmap->height)
672 height = bitmap->height - y;
675 sysFillRectangle(bitmap, x, y, width, height, color);
678 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
680 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
683 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
684 int width, int height)
686 if (DrawingOnBackground(x, y))
687 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
689 ClearRectangle(bitmap, x, y, width, height);
692 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
694 #if defined(TARGET_X11)
697 bitmap->clip_gc = clip_gc;
698 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
703 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
705 #if defined(TARGET_X11)
708 bitmap->clip_gc = clip_gc;
709 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
714 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
715 int src_x, int src_y, int width, int height,
716 int dst_x, int dst_y)
718 if (DrawingDeactivated(dst_x, dst_y, width, height))
721 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
722 dst_x, dst_y, BLIT_MASKED);
725 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
726 int src_x, int src_y, int width, int height,
727 int dst_x, int dst_y)
729 if (DrawingOnBackground(dst_x, dst_y))
731 /* draw background */
732 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
735 /* draw foreground */
736 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
737 dst_x - src_x, dst_y - src_y);
738 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
742 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
746 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
749 #if defined(TARGET_SDL)
750 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
752 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
756 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
759 #if defined(TARGET_SDL)
760 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
762 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
766 #if !defined(TARGET_X11_NATIVE)
767 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
768 int to_x, int to_y, Pixel pixel, int line_width)
772 for (x = 0; x < line_width; x++)
774 for (y = 0; y < line_width; y++)
776 int dx = x - line_width / 2;
777 int dy = y - line_width / 2;
779 if ((x == 0 && y == 0) ||
780 (x == 0 && y == line_width - 1) ||
781 (x == line_width - 1 && y == 0) ||
782 (x == line_width - 1 && y == line_width - 1))
785 #if defined(TARGET_SDL)
787 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
788 #elif defined(TARGET_ALLEGRO)
789 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
790 to_x + dx, to_y + dy, pixel);
797 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
799 #if !defined(TARGET_X11_NATIVE)
803 for (i = 0; i < num_points - 1; i++)
804 DrawLine(bitmap, points[i].x, points[i].y,
805 points[i + 1].x, points[i + 1].y, pixel, line_width);
808 SDLDrawLines(bitmap->surface, points, num_points, pixel);
811 XSetForeground(display, bitmap->line_gc[1], pixel);
812 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
813 (XPoint *)points, num_points, CoordModeOrigin);
817 Pixel GetPixel(Bitmap *bitmap, int x, int y)
819 if (x < 0 || x >= bitmap->width ||
820 y < 0 || y >= bitmap->height)
823 #if defined(TARGET_SDL)
824 return SDLGetPixel(bitmap, x, y);
825 #elif defined(TARGET_ALLEGRO)
826 return AllegroGetPixel(bitmap->drawable, x, y);
828 return X11GetPixel(bitmap, x, y);
832 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
833 unsigned int color_g, unsigned int color_b)
835 #if defined(TARGET_SDL)
836 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
837 #elif defined(TARGET_ALLEGRO)
838 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
840 return X11GetPixelFromRGB(color_r, color_g, color_b);
844 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
846 unsigned int color_r = (color >> 16) & 0xff;
847 unsigned int color_g = (color >> 8) & 0xff;
848 unsigned int color_b = (color >> 0) & 0xff;
850 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
853 /* execute all pending screen drawing operations */
854 void FlushDisplay(void)
861 /* execute and wait for all pending screen drawing operations */
862 void SyncDisplay(void)
865 XSync(display, FALSE);
869 void KeyboardAutoRepeatOn(void)
871 #if defined(TARGET_SDL)
872 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
873 SDL_DEFAULT_REPEAT_INTERVAL / 2);
874 SDL_EnableUNICODE(1);
877 XAutoRepeatOn(display);
881 void KeyboardAutoRepeatOff(void)
883 #if defined(TARGET_SDL)
884 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
885 SDL_EnableUNICODE(0);
888 XAutoRepeatOff(display);
892 boolean PointerInWindow(DrawWindow *window)
894 #if defined(TARGET_SDL)
902 /* if XQueryPointer() returns False, the pointer
903 is not on the same screen as the specified window */
904 return XQueryPointer(display, window->drawable, &root, &child,
905 &root_x, &root_y, &win_x, &win_y, &mask);
909 boolean SetVideoMode(boolean fullscreen)
911 #if defined(TARGET_SDL)
912 return SDLSetVideoMode(&backbuffer, fullscreen);
914 boolean success = TRUE;
916 if (fullscreen && video.fullscreen_available)
918 Error(ERR_WARN, "fullscreen not available in X11 version");
920 /* display error message only once */
921 video.fullscreen_available = FALSE;
930 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
932 #if defined(TARGET_SDL)
933 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
934 (!fullscreen && video.fullscreen_enabled))
935 fullscreen = SetVideoMode(fullscreen);
941 Bitmap *LoadImage(char *filename)
945 #if defined(TARGET_SDL)
946 new_bitmap = SDLLoadImage(filename);
948 new_bitmap = X11LoadImage(filename);
952 new_bitmap->source_filename = getStringCopy(filename);
957 Bitmap *LoadCustomImage(char *basename)
959 char *filename = getCustomImageFilename(basename);
962 if (filename == NULL)
963 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
965 if ((new_bitmap = LoadImage(filename)) == NULL)
966 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
971 void ReloadCustomImage(Bitmap *bitmap, char *basename)
973 char *filename = getCustomImageFilename(basename);
976 if (filename == NULL) /* (should never happen) */
978 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
982 if (strEqual(filename, bitmap->source_filename))
984 /* The old and new image are the same (have the same filename and path).
985 This usually means that this image does not exist in this graphic set
986 and a fallback to the existing image is done. */
991 if ((new_bitmap = LoadImage(filename)) == NULL)
993 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
997 if (bitmap->width != new_bitmap->width ||
998 bitmap->height != new_bitmap->height)
1000 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1002 FreeBitmap(new_bitmap);
1006 TransferBitmapPointers(new_bitmap, bitmap);
1010 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1012 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1014 #if defined(TARGET_SDL)
1015 SDLZoomBitmap(src_bitmap, dst_bitmap);
1017 X11ZoomBitmap(src_bitmap, dst_bitmap);
1023 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1024 boolean create_small_bitmaps)
1028 Bitmap *tmp_bitmap_1;
1029 Bitmap *tmp_bitmap_2;
1030 Bitmap *tmp_bitmap_4;
1031 Bitmap *tmp_bitmap_8;
1032 Bitmap *tmp_bitmap_16;
1033 Bitmap *tmp_bitmap_32;
1034 int width_1, height_1;
1035 int width_2, height_2;
1036 int width_4, height_4;
1037 int width_8, height_8;
1038 int width_16, height_16;
1039 int width_32, height_32;
1040 int new_width, new_height;
1042 /* calculate new image dimensions for normal sized image */
1043 width_1 = old_bitmap->width * zoom_factor;
1044 height_1 = old_bitmap->height * zoom_factor;
1046 /* get image with normal size (this might require scaling up) */
1047 if (zoom_factor != 1)
1048 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1050 tmp_bitmap_1 = old_bitmap;
1052 /* this is only needed to make compilers happy */
1053 tmp_bitmap_2 = NULL;
1054 tmp_bitmap_4 = NULL;
1055 tmp_bitmap_8 = NULL;
1056 tmp_bitmap_16 = NULL;
1057 tmp_bitmap_32 = NULL;
1059 if (create_small_bitmaps)
1061 /* calculate new image dimensions for small images */
1062 width_2 = width_1 / 2;
1063 height_2 = height_1 / 2;
1064 width_4 = width_1 / 4;
1065 height_4 = height_1 / 4;
1066 width_8 = width_1 / 8;
1067 height_8 = height_1 / 8;
1068 width_16 = width_1 / 16;
1069 height_16 = height_1 / 16;
1070 width_32 = width_1 / 32;
1071 height_32 = height_1 / 32;
1073 UPDATE_BUSY_STATE();
1075 /* get image with 1/2 of normal size (for use in the level editor) */
1076 if (zoom_factor != 2)
1077 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1079 tmp_bitmap_2 = old_bitmap;
1081 UPDATE_BUSY_STATE();
1083 /* get image with 1/4 of normal size (for use in the level editor) */
1084 if (zoom_factor != 4)
1085 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1087 tmp_bitmap_4 = old_bitmap;
1089 UPDATE_BUSY_STATE();
1091 /* get image with 1/8 of normal size (for use on the preview screen) */
1092 if (zoom_factor != 8)
1093 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1095 tmp_bitmap_8 = old_bitmap;
1097 UPDATE_BUSY_STATE();
1099 /* get image with 1/16 of normal size (for use on the preview screen) */
1100 if (zoom_factor != 16)
1101 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1103 tmp_bitmap_16 = old_bitmap;
1105 UPDATE_BUSY_STATE();
1107 /* get image with 1/32 of normal size (for use on the preview screen) */
1108 if (zoom_factor != 32)
1109 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1111 tmp_bitmap_32 = old_bitmap;
1113 UPDATE_BUSY_STATE();
1117 /* if image was scaled up, create new clipmask for normal size image */
1118 if (zoom_factor != 1)
1120 #if defined(TARGET_X11)
1121 if (old_bitmap->clip_mask)
1122 XFreePixmap(display, old_bitmap->clip_mask);
1124 old_bitmap->clip_mask =
1125 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1127 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1129 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1131 if (old_bitmap->surface_masked)
1132 SDL_FreeSurface(old_bitmap->surface_masked);
1134 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1135 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1136 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1137 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1138 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1143 if (create_small_bitmaps)
1145 new_width = width_1;
1146 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1148 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1150 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1151 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1153 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1154 width_1 / 2, height_1);
1155 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1156 3 * width_1 / 4, height_1);
1157 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1158 7 * width_1 / 8, height_1);
1159 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1160 15 * width_1 / 16, height_1);
1162 UPDATE_BUSY_STATE();
1166 new_width = width_1;
1167 new_height = height_1;
1169 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1172 if (create_small_bitmaps)
1174 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1175 if (zoom_factor != 1)
1176 FreeBitmap(tmp_bitmap_1);
1178 if (zoom_factor != 2)
1179 FreeBitmap(tmp_bitmap_2);
1181 if (zoom_factor != 4)
1182 FreeBitmap(tmp_bitmap_4);
1184 if (zoom_factor != 8)
1185 FreeBitmap(tmp_bitmap_8);
1187 if (zoom_factor != 16)
1188 FreeBitmap(tmp_bitmap_16);
1190 if (zoom_factor != 32)
1191 FreeBitmap(tmp_bitmap_32);
1194 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1195 #if defined(TARGET_SDL)
1196 swap_bitmap.surface = old_bitmap->surface;
1197 old_bitmap->surface = new_bitmap->surface;
1198 new_bitmap->surface = swap_bitmap.surface;
1200 swap_bitmap.drawable = old_bitmap->drawable;
1201 old_bitmap->drawable = new_bitmap->drawable;
1202 new_bitmap->drawable = swap_bitmap.drawable;
1205 old_bitmap->width = new_bitmap->width;
1206 old_bitmap->height = new_bitmap->height;
1209 /* this replaces all blit masks created when loading -- maybe optimize this */
1211 #if defined(TARGET_X11)
1212 if (old_bitmap->clip_mask)
1213 XFreePixmap(display, old_bitmap->clip_mask);
1215 old_bitmap->clip_mask =
1216 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1218 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1220 SDL_Surface *old_surface = old_bitmap->surface;
1222 if (old_bitmap->surface_masked)
1223 SDL_FreeSurface(old_bitmap->surface_masked);
1225 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1226 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1227 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1228 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1229 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1234 UPDATE_BUSY_STATE();
1236 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1239 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1241 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1244 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1246 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1250 /* ------------------------------------------------------------------------- */
1251 /* mouse pointer functions */
1252 /* ------------------------------------------------------------------------- */
1254 #if !defined(PLATFORM_MSDOS)
1255 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1256 /* XPM image definitions */
1257 static const char *cursor_image_none[] =
1259 /* width height num_colors chars_per_pixel */
1288 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1289 static const char *cursor_image_dot[] =
1291 /* width height num_colors chars_per_pixel */
1320 static const char **cursor_image_playfield = cursor_image_dot;
1322 /* some people complained about a "white dot" on the screen and thought it
1323 was a graphical error... OK, let's just remove the whole pointer :-) */
1324 static const char **cursor_image_playfield = cursor_image_none;
1327 #if defined(TARGET_SDL)
1328 static const int cursor_bit_order = BIT_ORDER_MSB;
1329 #elif defined(TARGET_X11_NATIVE)
1330 static const int cursor_bit_order = BIT_ORDER_LSB;
1333 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1335 struct MouseCursorInfo *cursor;
1336 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1337 int header_lines = 4;
1340 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1342 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1345 for (y = 0; y < cursor->width; y++)
1347 for (x = 0; x < cursor->height; x++)
1350 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1355 cursor->data[i] = cursor->mask[i] = 0;
1358 switch (image[header_lines + y][x])
1361 cursor->data[i] |= bit_mask;
1362 cursor->mask[i] |= bit_mask;
1366 cursor->mask[i] |= bit_mask;
1375 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1379 #endif /* !PLATFORM_MSDOS */
1381 void SetMouseCursor(int mode)
1383 #if !defined(PLATFORM_MSDOS)
1384 static struct MouseCursorInfo *cursor_none = NULL;
1385 static struct MouseCursorInfo *cursor_playfield = NULL;
1386 struct MouseCursorInfo *cursor_new;
1388 if (cursor_none == NULL)
1389 cursor_none = get_cursor_from_image(cursor_image_none);
1391 if (cursor_playfield == NULL)
1392 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1394 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1395 mode == CURSOR_NONE ? cursor_none :
1396 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1398 #if defined(TARGET_SDL)
1399 SDLSetMouseCursor(cursor_new);
1400 #elif defined(TARGET_X11_NATIVE)
1401 X11SetMouseCursor(cursor_new);
1407 /* ========================================================================= */
1408 /* audio functions */
1409 /* ========================================================================= */
1411 void OpenAudio(void)
1413 /* always start with reliable default values */
1414 audio.sound_available = FALSE;
1415 audio.music_available = FALSE;
1416 audio.loops_available = FALSE;
1418 audio.sound_enabled = FALSE;
1419 audio.sound_deactivated = FALSE;
1421 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1422 audio.mixer_pid = 0;
1423 audio.device_name = NULL;
1424 audio.device_fd = -1;
1426 audio.num_channels = 0;
1427 audio.music_channel = 0;
1428 audio.first_sound_channel = 0;
1430 #if defined(TARGET_SDL)
1432 #elif defined(PLATFORM_UNIX)
1434 #elif defined(PLATFORM_MSDOS)
1439 void CloseAudio(void)
1441 #if defined(TARGET_SDL)
1443 #elif defined(PLATFORM_UNIX)
1445 #elif defined(PLATFORM_MSDOS)
1449 audio.sound_enabled = FALSE;
1452 void SetAudioMode(boolean enabled)
1454 if (!audio.sound_available)
1457 audio.sound_enabled = enabled;
1461 /* ========================================================================= */
1462 /* event functions */
1463 /* ========================================================================= */
1465 void InitEventFilter(EventFilter filter_function)
1467 #if defined(TARGET_SDL)
1468 /* set event filter to filter out certain events */
1469 SDL_SetEventFilter(filter_function);
1473 boolean PendingEvent(void)
1475 #if defined(TARGET_SDL)
1476 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1478 return (XPending(display) ? TRUE : FALSE);
1482 void NextEvent(Event *event)
1484 #if defined(TARGET_SDL)
1485 SDLNextEvent(event);
1487 XNextEvent(display, event);
1491 void PeekEvent(Event *event)
1493 #if defined(TARGET_SDL)
1494 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1496 XPeekEvent(display, event);
1500 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1502 #if defined(TARGET_SDL)
1505 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1506 (int)event->keysym.unicode,
1507 (int)event->keysym.sym,
1508 (int)SDL_GetModState());
1511 if (with_modifiers &&
1512 event->keysym.unicode > 0x0000 &&
1513 event->keysym.unicode < 0x2000)
1514 return event->keysym.unicode;
1516 return event->keysym.sym;
1521 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1522 (int)XLookupKeysym(event, event->state),
1523 (int)XLookupKeysym(event, 0));
1527 return XLookupKeysym(event, event->state);
1529 return XLookupKeysym(event, 0);
1533 KeyMod HandleKeyModState(Key key, int key_status)
1535 static KeyMod current_modifiers = KMOD_None;
1537 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1539 KeyMod new_modifier = KMOD_None;
1544 new_modifier = KMOD_Shift_L;
1547 new_modifier = KMOD_Shift_R;
1549 case KSYM_Control_L:
1550 new_modifier = KMOD_Control_L;
1552 case KSYM_Control_R:
1553 new_modifier = KMOD_Control_R;
1556 new_modifier = KMOD_Meta_L;
1559 new_modifier = KMOD_Meta_R;
1562 new_modifier = KMOD_Alt_L;
1565 new_modifier = KMOD_Alt_R;
1571 if (key_status == KEY_PRESSED)
1572 current_modifiers |= new_modifier;
1574 current_modifiers &= ~new_modifier;
1577 return current_modifiers;
1580 KeyMod GetKeyModState()
1582 #if defined(TARGET_SDL)
1583 return (KeyMod)SDL_GetModState();
1585 return HandleKeyModState(KSYM_UNDEFINED, 0);
1589 KeyMod GetKeyModStateFromEvents()
1591 /* always use key modifier state as tracked from key events (this is needed
1592 if the modifier key event was injected into the event queue, but the key
1593 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1594 query the keys as held pressed on the keyboard) -- this case is currently
1595 only used to filter out clipboard insert events from "True X-Mouse" tool */
1597 return HandleKeyModState(KSYM_UNDEFINED, 0);
1600 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1602 if (event->type != EVENT_CLIENTMESSAGE)
1605 #if defined(TARGET_SDL)
1606 return TRUE; /* the only possible message here is SDL_QUIT */
1607 #elif defined(PLATFORM_UNIX)
1608 if ((event->window == window->drawable) &&
1609 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1617 /* ========================================================================= */
1618 /* joystick functions */
1619 /* ========================================================================= */
1621 void InitJoysticks()
1625 #if defined(NO_JOYSTICK)
1626 return; /* joysticks generally deactivated by compile-time directive */
1629 /* always start with reliable default values */
1630 joystick.status = JOYSTICK_NOT_AVAILABLE;
1631 for (i = 0; i < MAX_PLAYERS; i++)
1632 joystick.fd[i] = -1; /* joystick device closed */
1634 #if defined(TARGET_SDL)
1636 #elif defined(PLATFORM_UNIX)
1637 UnixInitJoysticks();
1638 #elif defined(PLATFORM_MSDOS)
1639 MSDOSInitJoysticks();
1643 for (i = 0; i < MAX_PLAYERS; i++)
1644 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1648 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1650 #if defined(TARGET_SDL)
1651 return SDLReadJoystick(nr, x, y, b1, b2);
1652 #elif defined(PLATFORM_UNIX)
1653 return UnixReadJoystick(nr, x, y, b1, b2);
1654 #elif defined(PLATFORM_MSDOS)
1655 return MSDOSReadJoystick(nr, x, y, b1, b2);