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)
535 *width = bitmap->width - *x;
543 else if (*y + *height > bitmap->height)
545 *height = bitmap->height - *y;
551 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
552 int src_x, int src_y, int width, int height,
553 int dst_x, int dst_y)
555 int dst_x_unclipped = dst_x;
556 int dst_y_unclipped = dst_y;
558 if (DrawingDeactivated(dst_x, dst_y, width, height))
562 if (!ValidClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height) ||
563 !ValidClippedRectangle(dst_bitmap, &dst_x, &dst_y, &width, &height))
566 /* source x/y might need adjustment if destination x/y was clipped top/left */
567 src_x += dst_x - dst_x_unclipped;
568 src_y += dst_y - dst_y_unclipped;
571 /* skip if rectangle starts outside bitmap */
572 if (src_x >= src_bitmap->width ||
573 src_y >= src_bitmap->height ||
574 dst_x >= dst_bitmap->width ||
575 dst_y >= dst_bitmap->height)
578 /* clip if rectangle overlaps bitmap */
579 if (src_x + width > src_bitmap->width)
580 width = src_bitmap->width - src_x;
581 if (src_y + height > src_bitmap->height)
582 height = src_bitmap->height - src_y;
583 if (dst_x + width > dst_bitmap->width)
584 width = dst_bitmap->width - dst_x;
585 if (dst_y + height > dst_bitmap->height)
586 height = dst_bitmap->height - dst_y;
590 /* !!! 2009-03-30: Fixed by using self-compiled, patched SDL.dll !!! */
591 /* (This bug still exists in the actual (as of 2009-06-15) version 1.2.13,
592 but is already fixed in SVN and should therefore finally be fixed with
593 the next official SDL release, which is probably version 1.2.14.) */
595 /* !!! 2009-03-24: It seems that this problem still exists in 1.2.12 !!! */
596 #if defined(TARGET_SDL) && defined(PLATFORM_WIN32)
597 if (src_bitmap == dst_bitmap)
599 /* !!! THIS IS A BUG (IN THE SDL LIBRARY?) AND SHOULD BE FIXED !!! */
601 /* needed when blitting directly to same bitmap -- should not be needed with
602 recent SDL libraries, but apparently does not work in 1.2.11 directly */
604 static Bitmap *tmp_bitmap = NULL;
605 static int tmp_bitmap_xsize = 0;
606 static int tmp_bitmap_ysize = 0;
608 /* start with largest static bitmaps for initial bitmap size ... */
609 if (tmp_bitmap_xsize == 0 && tmp_bitmap_ysize == 0)
611 tmp_bitmap_xsize = MAX(gfx.win_xsize, gfx.scrollbuffer_width);
612 tmp_bitmap_ysize = MAX(gfx.win_ysize, gfx.scrollbuffer_height);
615 /* ... and allow for later re-adjustments due to custom artwork bitmaps */
616 if (src_bitmap->width > tmp_bitmap_xsize ||
617 src_bitmap->height > tmp_bitmap_ysize)
619 tmp_bitmap_xsize = MAX(tmp_bitmap_xsize, src_bitmap->width);
620 tmp_bitmap_ysize = MAX(tmp_bitmap_ysize, src_bitmap->height);
622 FreeBitmap(tmp_bitmap);
627 if (tmp_bitmap == NULL)
628 tmp_bitmap = CreateBitmap(tmp_bitmap_xsize, tmp_bitmap_ysize,
631 sysCopyArea(src_bitmap, tmp_bitmap,
632 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
633 sysCopyArea(tmp_bitmap, dst_bitmap,
634 dst_x, dst_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
642 sysCopyArea(src_bitmap, dst_bitmap,
643 src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE);
646 void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height,
647 int fade_mode, int fade_delay, int post_delay,
648 void (*draw_border_function)(void))
651 /* (use bitmap "backbuffer" -- "bitmap_cross" may be undefined) */
652 if (!ValidClippedRectangle(backbuffer, &x, &y, &width, &height))
656 #if defined(TARGET_SDL)
657 SDLFadeRectangle(bitmap_cross, x, y, width, height,
658 fade_mode, fade_delay, post_delay, draw_border_function);
660 X11FadeRectangle(bitmap_cross, x, y, width, height,
661 fade_mode, fade_delay, post_delay, draw_border_function);
665 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
668 if (DrawingDeactivated(x, y, width, height))
672 if (!ValidClippedRectangle(bitmap, &x, &y, &width, &height))
675 /* skip if rectangle starts outside bitmap */
676 if (x >= bitmap->width ||
680 /* clip if rectangle overlaps bitmap */
681 if (x + width > bitmap->width)
682 width = bitmap->width - x;
683 if (y + height > bitmap->height)
684 height = bitmap->height - y;
687 sysFillRectangle(bitmap, x, y, width, height, color);
690 void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
692 FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
695 void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
696 int width, int height)
698 if (DrawingOnBackground(x, y))
699 BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
701 ClearRectangle(bitmap, x, y, width, height);
704 void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
706 #if defined(TARGET_X11)
709 bitmap->clip_gc = clip_gc;
710 XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
715 void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
717 #if defined(TARGET_X11)
720 bitmap->clip_gc = clip_gc;
721 XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
726 void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
727 int src_x, int src_y, int width, int height,
728 int dst_x, int dst_y)
730 if (DrawingDeactivated(dst_x, dst_y, width, height))
733 sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
734 dst_x, dst_y, BLIT_MASKED);
737 void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
738 int src_x, int src_y, int width, int height,
739 int dst_x, int dst_y)
741 if (DrawingOnBackground(dst_x, dst_y))
743 /* draw background */
744 BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
747 /* draw foreground */
748 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
749 dst_x - src_x, dst_y - src_y);
750 BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
754 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
758 void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
761 #if defined(TARGET_SDL)
762 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
764 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
768 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
771 #if defined(TARGET_SDL)
772 SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
774 X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
778 #if !defined(TARGET_X11_NATIVE)
779 void DrawLine(Bitmap *bitmap, int from_x, int from_y,
780 int to_x, int to_y, Pixel pixel, int line_width)
784 for (x = 0; x < line_width; x++)
786 for (y = 0; y < line_width; y++)
788 int dx = x - line_width / 2;
789 int dy = y - line_width / 2;
791 if ((x == 0 && y == 0) ||
792 (x == 0 && y == line_width - 1) ||
793 (x == line_width - 1 && y == 0) ||
794 (x == line_width - 1 && y == line_width - 1))
797 #if defined(TARGET_SDL)
799 from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel);
800 #elif defined(TARGET_ALLEGRO)
801 AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy,
802 to_x + dx, to_y + dy, pixel);
809 void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
811 #if !defined(TARGET_X11_NATIVE)
815 for (i = 0; i < num_points - 1; i++)
816 DrawLine(bitmap, points[i].x, points[i].y,
817 points[i + 1].x, points[i + 1].y, pixel, line_width);
820 SDLDrawLines(bitmap->surface, points, num_points, pixel);
823 XSetForeground(display, bitmap->line_gc[1], pixel);
824 XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
825 (XPoint *)points, num_points, CoordModeOrigin);
829 Pixel GetPixel(Bitmap *bitmap, int x, int y)
831 if (x < 0 || x >= bitmap->width ||
832 y < 0 || y >= bitmap->height)
835 #if defined(TARGET_SDL)
836 return SDLGetPixel(bitmap, x, y);
837 #elif defined(TARGET_ALLEGRO)
838 return AllegroGetPixel(bitmap->drawable, x, y);
840 return X11GetPixel(bitmap, x, y);
844 Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
845 unsigned int color_g, unsigned int color_b)
847 #if defined(TARGET_SDL)
848 return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
849 #elif defined(TARGET_ALLEGRO)
850 return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
852 return X11GetPixelFromRGB(color_r, color_g, color_b);
856 Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
858 unsigned int color_r = (color >> 16) & 0xff;
859 unsigned int color_g = (color >> 8) & 0xff;
860 unsigned int color_b = (color >> 0) & 0xff;
862 return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
865 /* execute all pending screen drawing operations */
866 void FlushDisplay(void)
873 /* execute and wait for all pending screen drawing operations */
874 void SyncDisplay(void)
877 XSync(display, FALSE);
881 void KeyboardAutoRepeatOn(void)
883 #if defined(TARGET_SDL)
884 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
885 SDL_DEFAULT_REPEAT_INTERVAL / 2);
886 SDL_EnableUNICODE(1);
889 XAutoRepeatOn(display);
893 void KeyboardAutoRepeatOff(void)
895 #if defined(TARGET_SDL)
896 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
897 SDL_EnableUNICODE(0);
900 XAutoRepeatOff(display);
904 boolean PointerInWindow(DrawWindow *window)
906 #if defined(TARGET_SDL)
914 /* if XQueryPointer() returns False, the pointer
915 is not on the same screen as the specified window */
916 return XQueryPointer(display, window->drawable, &root, &child,
917 &root_x, &root_y, &win_x, &win_y, &mask);
921 boolean SetVideoMode(boolean fullscreen)
923 #if defined(TARGET_SDL)
924 return SDLSetVideoMode(&backbuffer, fullscreen);
926 boolean success = TRUE;
928 if (fullscreen && video.fullscreen_available)
930 Error(ERR_WARN, "fullscreen not available in X11 version");
932 /* display error message only once */
933 video.fullscreen_available = FALSE;
942 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
944 #if defined(TARGET_SDL)
945 if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
946 (!fullscreen && video.fullscreen_enabled))
947 fullscreen = SetVideoMode(fullscreen);
953 Bitmap *LoadImage(char *filename)
957 #if defined(TARGET_SDL)
958 new_bitmap = SDLLoadImage(filename);
960 new_bitmap = X11LoadImage(filename);
964 new_bitmap->source_filename = getStringCopy(filename);
969 Bitmap *LoadCustomImage(char *basename)
971 char *filename = getCustomImageFilename(basename);
974 if (filename == NULL)
975 Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename);
977 if ((new_bitmap = LoadImage(filename)) == NULL)
978 Error(ERR_EXIT, "LoadImage() failed: %s", GetError());
983 void ReloadCustomImage(Bitmap *bitmap, char *basename)
985 char *filename = getCustomImageFilename(basename);
988 if (filename == NULL) /* (should never happen) */
990 Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename);
994 if (strEqual(filename, bitmap->source_filename))
996 /* The old and new image are the same (have the same filename and path).
997 This usually means that this image does not exist in this graphic set
998 and a fallback to the existing image is done. */
1003 if ((new_bitmap = LoadImage(filename)) == NULL)
1005 Error(ERR_WARN, "LoadImage() failed: %s", GetError());
1009 if (bitmap->width != new_bitmap->width ||
1010 bitmap->height != new_bitmap->height)
1012 Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
1014 FreeBitmap(new_bitmap);
1018 TransferBitmapPointers(new_bitmap, bitmap);
1022 Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
1024 Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
1026 #if defined(TARGET_SDL)
1027 SDLZoomBitmap(src_bitmap, dst_bitmap);
1029 X11ZoomBitmap(src_bitmap, dst_bitmap);
1035 static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
1036 boolean create_small_bitmaps)
1040 Bitmap *tmp_bitmap_1;
1041 Bitmap *tmp_bitmap_2;
1042 Bitmap *tmp_bitmap_4;
1043 Bitmap *tmp_bitmap_8;
1044 Bitmap *tmp_bitmap_16;
1045 Bitmap *tmp_bitmap_32;
1046 int width_1, height_1;
1047 int width_2, height_2;
1048 int width_4, height_4;
1049 int width_8, height_8;
1050 int width_16, height_16;
1051 int width_32, height_32;
1052 int new_width, new_height;
1054 /* calculate new image dimensions for normal sized image */
1055 width_1 = old_bitmap->width * zoom_factor;
1056 height_1 = old_bitmap->height * zoom_factor;
1058 /* get image with normal size (this might require scaling up) */
1059 if (zoom_factor != 1)
1060 tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1);
1062 tmp_bitmap_1 = old_bitmap;
1064 /* this is only needed to make compilers happy */
1065 tmp_bitmap_2 = NULL;
1066 tmp_bitmap_4 = NULL;
1067 tmp_bitmap_8 = NULL;
1068 tmp_bitmap_16 = NULL;
1069 tmp_bitmap_32 = NULL;
1071 if (create_small_bitmaps)
1073 /* calculate new image dimensions for small images */
1074 width_2 = width_1 / 2;
1075 height_2 = height_1 / 2;
1076 width_4 = width_1 / 4;
1077 height_4 = height_1 / 4;
1078 width_8 = width_1 / 8;
1079 height_8 = height_1 / 8;
1080 width_16 = width_1 / 16;
1081 height_16 = height_1 / 16;
1082 width_32 = width_1 / 32;
1083 height_32 = height_1 / 32;
1085 UPDATE_BUSY_STATE();
1087 /* get image with 1/2 of normal size (for use in the level editor) */
1088 if (zoom_factor != 2)
1089 tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
1091 tmp_bitmap_2 = old_bitmap;
1093 UPDATE_BUSY_STATE();
1095 /* get image with 1/4 of normal size (for use in the level editor) */
1096 if (zoom_factor != 4)
1097 tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2);
1099 tmp_bitmap_4 = old_bitmap;
1101 UPDATE_BUSY_STATE();
1103 /* get image with 1/8 of normal size (for use on the preview screen) */
1104 if (zoom_factor != 8)
1105 tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2);
1107 tmp_bitmap_8 = old_bitmap;
1109 UPDATE_BUSY_STATE();
1111 /* get image with 1/16 of normal size (for use on the preview screen) */
1112 if (zoom_factor != 16)
1113 tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2);
1115 tmp_bitmap_16 = old_bitmap;
1117 UPDATE_BUSY_STATE();
1119 /* get image with 1/32 of normal size (for use on the preview screen) */
1120 if (zoom_factor != 32)
1121 tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2);
1123 tmp_bitmap_32 = old_bitmap;
1125 UPDATE_BUSY_STATE();
1129 /* if image was scaled up, create new clipmask for normal size image */
1130 if (zoom_factor != 1)
1132 #if defined(TARGET_X11)
1133 if (old_bitmap->clip_mask)
1134 XFreePixmap(display, old_bitmap->clip_mask);
1136 old_bitmap->clip_mask =
1137 Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1);
1139 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1141 SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface;
1143 if (old_bitmap->surface_masked)
1144 SDL_FreeSurface(old_bitmap->surface_masked);
1146 SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY,
1147 SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00));
1148 if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL)
1149 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1150 SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */
1155 if (create_small_bitmaps)
1157 new_width = width_1;
1158 new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */
1160 new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
1162 BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
1163 BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
1165 BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4,
1166 width_1 / 2, height_1);
1167 BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
1168 3 * width_1 / 4, height_1);
1169 BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16,
1170 7 * width_1 / 8, height_1);
1171 BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32,
1172 15 * width_1 / 16, height_1);
1174 UPDATE_BUSY_STATE();
1178 new_width = width_1;
1179 new_height = height_1;
1181 new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
1184 if (create_small_bitmaps)
1186 /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
1187 if (zoom_factor != 1)
1188 FreeBitmap(tmp_bitmap_1);
1190 if (zoom_factor != 2)
1191 FreeBitmap(tmp_bitmap_2);
1193 if (zoom_factor != 4)
1194 FreeBitmap(tmp_bitmap_4);
1196 if (zoom_factor != 8)
1197 FreeBitmap(tmp_bitmap_8);
1199 if (zoom_factor != 16)
1200 FreeBitmap(tmp_bitmap_16);
1202 if (zoom_factor != 32)
1203 FreeBitmap(tmp_bitmap_32);
1206 /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */
1207 #if defined(TARGET_SDL)
1208 swap_bitmap.surface = old_bitmap->surface;
1209 old_bitmap->surface = new_bitmap->surface;
1210 new_bitmap->surface = swap_bitmap.surface;
1212 swap_bitmap.drawable = old_bitmap->drawable;
1213 old_bitmap->drawable = new_bitmap->drawable;
1214 new_bitmap->drawable = swap_bitmap.drawable;
1217 old_bitmap->width = new_bitmap->width;
1218 old_bitmap->height = new_bitmap->height;
1221 /* this replaces all blit masks created when loading -- maybe optimize this */
1223 #if defined(TARGET_X11)
1224 if (old_bitmap->clip_mask)
1225 XFreePixmap(display, old_bitmap->clip_mask);
1227 old_bitmap->clip_mask =
1228 Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height);
1230 XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask);
1232 SDL_Surface *old_surface = old_bitmap->surface;
1234 if (old_bitmap->surface_masked)
1235 SDL_FreeSurface(old_bitmap->surface_masked);
1237 SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY,
1238 SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00));
1239 if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL)
1240 Error(ERR_EXIT, "SDL_DisplayFormat() failed");
1241 SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */
1246 UPDATE_BUSY_STATE();
1248 FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */
1251 void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
1253 CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
1256 void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
1258 CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
1262 /* ------------------------------------------------------------------------- */
1263 /* mouse pointer functions */
1264 /* ------------------------------------------------------------------------- */
1266 #if !defined(PLATFORM_MSDOS)
1267 #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0
1268 /* XPM image definitions */
1269 static const char *cursor_image_none[] =
1271 /* width height num_colors chars_per_pixel */
1300 #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER
1301 static const char *cursor_image_dot[] =
1303 /* width height num_colors chars_per_pixel */
1332 static const char **cursor_image_playfield = cursor_image_dot;
1334 /* some people complained about a "white dot" on the screen and thought it
1335 was a graphical error... OK, let's just remove the whole pointer :-) */
1336 static const char **cursor_image_playfield = cursor_image_none;
1339 #if defined(TARGET_SDL)
1340 static const int cursor_bit_order = BIT_ORDER_MSB;
1341 #elif defined(TARGET_X11_NATIVE)
1342 static const int cursor_bit_order = BIT_ORDER_LSB;
1345 static struct MouseCursorInfo *get_cursor_from_image(const char **image)
1347 struct MouseCursorInfo *cursor;
1348 boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
1349 int header_lines = 4;
1352 cursor = checked_calloc(sizeof(struct MouseCursorInfo));
1354 sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
1357 for (y = 0; y < cursor->width; y++)
1359 for (x = 0; x < cursor->height; x++)
1362 int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
1367 cursor->data[i] = cursor->mask[i] = 0;
1370 switch (image[header_lines + y][x])
1373 cursor->data[i] |= bit_mask;
1374 cursor->mask[i] |= bit_mask;
1378 cursor->mask[i] |= bit_mask;
1387 sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
1391 #endif /* !PLATFORM_MSDOS */
1393 void SetMouseCursor(int mode)
1395 #if !defined(PLATFORM_MSDOS)
1396 static struct MouseCursorInfo *cursor_none = NULL;
1397 static struct MouseCursorInfo *cursor_playfield = NULL;
1398 struct MouseCursorInfo *cursor_new;
1400 if (cursor_none == NULL)
1401 cursor_none = get_cursor_from_image(cursor_image_none);
1403 if (cursor_playfield == NULL)
1404 cursor_playfield = get_cursor_from_image(cursor_image_playfield);
1406 cursor_new = (mode == CURSOR_DEFAULT ? NULL :
1407 mode == CURSOR_NONE ? cursor_none :
1408 mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
1410 #if defined(TARGET_SDL)
1411 SDLSetMouseCursor(cursor_new);
1412 #elif defined(TARGET_X11_NATIVE)
1413 X11SetMouseCursor(cursor_new);
1419 /* ========================================================================= */
1420 /* audio functions */
1421 /* ========================================================================= */
1423 void OpenAudio(void)
1425 /* always start with reliable default values */
1426 audio.sound_available = FALSE;
1427 audio.music_available = FALSE;
1428 audio.loops_available = FALSE;
1430 audio.sound_enabled = FALSE;
1431 audio.sound_deactivated = FALSE;
1433 audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
1434 audio.mixer_pid = 0;
1435 audio.device_name = NULL;
1436 audio.device_fd = -1;
1438 audio.num_channels = 0;
1439 audio.music_channel = 0;
1440 audio.first_sound_channel = 0;
1442 #if defined(TARGET_SDL)
1444 #elif defined(PLATFORM_UNIX)
1446 #elif defined(PLATFORM_MSDOS)
1451 void CloseAudio(void)
1453 #if defined(TARGET_SDL)
1455 #elif defined(PLATFORM_UNIX)
1457 #elif defined(PLATFORM_MSDOS)
1461 audio.sound_enabled = FALSE;
1464 void SetAudioMode(boolean enabled)
1466 if (!audio.sound_available)
1469 audio.sound_enabled = enabled;
1473 /* ========================================================================= */
1474 /* event functions */
1475 /* ========================================================================= */
1477 void InitEventFilter(EventFilter filter_function)
1479 #if defined(TARGET_SDL)
1480 /* set event filter to filter out certain events */
1481 SDL_SetEventFilter(filter_function);
1485 boolean PendingEvent(void)
1487 #if defined(TARGET_SDL)
1488 return (SDL_PollEvent(NULL) ? TRUE : FALSE);
1490 return (XPending(display) ? TRUE : FALSE);
1494 void NextEvent(Event *event)
1496 #if defined(TARGET_SDL)
1497 SDLNextEvent(event);
1499 XNextEvent(display, event);
1503 void PeekEvent(Event *event)
1505 #if defined(TARGET_SDL)
1506 SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
1508 XPeekEvent(display, event);
1512 Key GetEventKey(KeyEvent *event, boolean with_modifiers)
1514 #if defined(TARGET_SDL)
1517 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
1518 (int)event->keysym.unicode,
1519 (int)event->keysym.sym,
1520 (int)SDL_GetModState());
1523 if (with_modifiers &&
1524 event->keysym.unicode > 0x0000 &&
1525 event->keysym.unicode < 0x2000)
1526 return event->keysym.unicode;
1528 return event->keysym.sym;
1533 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
1534 (int)XLookupKeysym(event, event->state),
1535 (int)XLookupKeysym(event, 0));
1539 return XLookupKeysym(event, event->state);
1541 return XLookupKeysym(event, 0);
1545 KeyMod HandleKeyModState(Key key, int key_status)
1547 static KeyMod current_modifiers = KMOD_None;
1549 if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */
1551 KeyMod new_modifier = KMOD_None;
1556 new_modifier = KMOD_Shift_L;
1559 new_modifier = KMOD_Shift_R;
1561 case KSYM_Control_L:
1562 new_modifier = KMOD_Control_L;
1564 case KSYM_Control_R:
1565 new_modifier = KMOD_Control_R;
1568 new_modifier = KMOD_Meta_L;
1571 new_modifier = KMOD_Meta_R;
1574 new_modifier = KMOD_Alt_L;
1577 new_modifier = KMOD_Alt_R;
1583 if (key_status == KEY_PRESSED)
1584 current_modifiers |= new_modifier;
1586 current_modifiers &= ~new_modifier;
1589 return current_modifiers;
1592 KeyMod GetKeyModState()
1594 #if defined(TARGET_SDL)
1595 return (KeyMod)SDL_GetModState();
1597 return HandleKeyModState(KSYM_UNDEFINED, 0);
1601 KeyMod GetKeyModStateFromEvents()
1603 /* always use key modifier state as tracked from key events (this is needed
1604 if the modifier key event was injected into the event queue, but the key
1605 was not really pressed on keyboard -- SDL_GetModState() seems to directly
1606 query the keys as held pressed on the keyboard) -- this case is currently
1607 only used to filter out clipboard insert events from "True X-Mouse" tool */
1609 return HandleKeyModState(KSYM_UNDEFINED, 0);
1612 boolean CheckCloseWindowEvent(ClientMessageEvent *event)
1614 if (event->type != EVENT_CLIENTMESSAGE)
1617 #if defined(TARGET_SDL)
1618 return TRUE; /* the only possible message here is SDL_QUIT */
1619 #elif defined(PLATFORM_UNIX)
1620 if ((event->window == window->drawable) &&
1621 (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
1629 /* ========================================================================= */
1630 /* joystick functions */
1631 /* ========================================================================= */
1633 void InitJoysticks()
1637 #if defined(NO_JOYSTICK)
1638 return; /* joysticks generally deactivated by compile-time directive */
1641 /* always start with reliable default values */
1642 joystick.status = JOYSTICK_NOT_AVAILABLE;
1643 for (i = 0; i < MAX_PLAYERS; i++)
1644 joystick.fd[i] = -1; /* joystick device closed */
1646 #if defined(TARGET_SDL)
1648 #elif defined(PLATFORM_UNIX)
1649 UnixInitJoysticks();
1650 #elif defined(PLATFORM_MSDOS)
1651 MSDOSInitJoysticks();
1655 for (i = 0; i < MAX_PLAYERS; i++)
1656 printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
1660 boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
1662 #if defined(TARGET_SDL)
1663 return SDLReadJoystick(nr, x, y, b1, b2);
1664 #elif defined(PLATFORM_UNIX)
1665 return UnixReadJoystick(nr, x, y, b1, b2);
1666 #elif defined(PLATFORM_MSDOS)
1667 return MSDOSReadJoystick(nr, x, y, b1, b2);