/*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* * (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * * Germany * * e-mail: info@artsoft.org * *----------------------------------------------------------* * system.c * ***********************************************************/ #include #include #include "platform.h" #if defined(PLATFORM_MSDOS) #include #endif #include "system.h" #include "image.h" #include "sound.h" #include "setup.h" #include "joystick.h" #include "misc.h" /* ========================================================================= */ /* exported variables */ /* ========================================================================= */ struct ProgramInfo program; struct OptionInfo options; struct VideoSystemInfo video; struct AudioSystemInfo audio; struct GfxInfo gfx; struct ArtworkInfo artwork; struct JoystickInfo joystick; struct SetupInfo setup; LevelDirTree *leveldir_first_all = NULL; LevelDirTree *leveldir_first = NULL; LevelDirTree *leveldir_current = NULL; int level_nr; Display *display = NULL; Visual *visual = NULL; int screen = 0; Colormap cmap = None; DrawWindow *window = NULL; DrawBuffer *backbuffer = NULL; DrawBuffer *drawto = NULL; int button_status = MB_NOT_PRESSED; boolean motion_status = FALSE; int redraw_mask = REDRAW_NONE; int redraw_tiles = 0; int FrameCounter = 0; /* ========================================================================= */ /* init/close functions */ /* ========================================================================= */ void InitProgramInfo(char *argv0, char *userdata_subdir, char *userdata_subdir_unix, char *program_title, char *window_title, char *icon_title, char *x11_icon_filename, char *x11_iconmask_filename, char *sdl_icon_filename, char *msdos_cursor_filename, char *cookie_prefix, char *filename_prefix, int program_version) { program.command_basepath = getBasePath(argv0); program.command_basename = getBaseName(argv0); program.userdata_subdir = userdata_subdir; program.userdata_subdir_unix = userdata_subdir_unix; program.userdata_path = getUserGameDataDir(); program.program_title = program_title; program.window_title = window_title; program.icon_title = icon_title; program.x11_icon_filename = x11_icon_filename; program.x11_iconmask_filename = x11_iconmask_filename; program.sdl_icon_filename = sdl_icon_filename; program.msdos_cursor_filename = msdos_cursor_filename; program.cookie_prefix = cookie_prefix; program.filename_prefix = filename_prefix; program.version_major = VERSION_MAJOR(program_version); program.version_minor = VERSION_MINOR(program_version); program.version_patch = VERSION_PATCH(program_version); program.error_filename = getErrorFilename(ERROR_BASENAME); program.error_file = stderr; } void InitExitFunction(void (*exit_function)(int)) { program.exit_function = exit_function; /* set signal handlers to custom exit function */ signal(SIGINT, exit_function); signal(SIGTERM, exit_function); #if defined(TARGET_SDL) /* set exit function to automatically cleanup SDL stuff after exit() */ atexit(SDL_Quit); #endif } void InitPlatformDependentStuff(void) { #if defined(PLATFORM_MSDOS) _fmode = O_BINARY; #endif #if defined(PLATFORM_MACOSX) updateUserGameDataDir(); #endif #if !defined(PLATFORM_UNIX) || defined(PLATFORM_MACOSX) openErrorFile(); #endif #if defined(TARGET_SDL) if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0) Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError()); SDLNet_Init(); #endif } void ClosePlatformDependentStuff(void) { #if defined(PLATFORM_WIN32) || defined(PLATFORM_MSDOS) closeErrorFile(); #endif #if defined(PLATFORM_MSDOS) dumpErrorFile(); #endif } void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize, int real_sx, int real_sy, int full_sxsize, int full_sysize, Bitmap *field_save_buffer) { gfx.sx = sx; gfx.sy = sy; gfx.sxsize = sxsize; gfx.sysize = sysize; gfx.real_sx = real_sx; gfx.real_sy = real_sy; gfx.full_sxsize = full_sxsize; gfx.full_sysize = full_sysize; gfx.field_save_buffer = field_save_buffer; gfx.background_bitmap = NULL; gfx.background_bitmap_mask = REDRAW_NONE; SetDrawDeactivationMask(REDRAW_NONE); /* do not deactivate drawing */ SetDrawBackgroundMask(REDRAW_NONE); /* deactivate masked drawing */ } void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize) { gfx.dx = dx; gfx.dy = dy; gfx.dxsize = dxsize; gfx.dysize = dysize; } void InitGfxDoor2Info(int vx, int vy, int vxsize, int vysize) { gfx.vx = vx; gfx.vy = vy; gfx.vxsize = vxsize; gfx.vysize = vysize; } void InitGfxScrollbufferInfo(int scrollbuffer_width, int scrollbuffer_height) { /* currently only used by MSDOS code to alloc VRAM buffer, if available */ gfx.scrollbuffer_width = scrollbuffer_width; gfx.scrollbuffer_height = scrollbuffer_height; } void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void)) { gfx.draw_busy_anim_function = draw_busy_anim_function; } void SetDrawDeactivationMask(int draw_deactivation_mask) { gfx.draw_deactivation_mask = draw_deactivation_mask; } void SetDrawBackgroundMask(int draw_background_mask) { gfx.draw_background_mask = draw_background_mask; } static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile, int dest_x, int dest_y, int width, int height) { int bitmap_xsize = width; int bitmap_ysize = height; int tile_xsize = tile->width; int tile_ysize = tile->height; int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize; int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize; int x, y; for (y = 0; y < tile_ysteps; y++) { for (x = 0; x < tile_xsteps; x++) { int draw_x = dest_x + x * tile_xsize; int draw_y = dest_y + y * tile_ysize; int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize); int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize); BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y); } } } void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask) { if (background_bitmap_tile != NULL) gfx.background_bitmap_mask |= mask; else gfx.background_bitmap_mask &= ~mask; if (gfx.background_bitmap == NULL) gfx.background_bitmap = CreateBitmap(video.width, video.height, DEFAULT_DEPTH); if (background_bitmap_tile == NULL) /* empty background requested */ return; if (mask == REDRAW_ALL) DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, 0, 0, video.width, video.height); else if (mask == REDRAW_FIELD) DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize); else if (mask == REDRAW_DOOR_1) { DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile, gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize); } } void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove every mask before setting mask for window */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, 0xffff); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL); } void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for main area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD); } void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile) { /* remove window area mask before setting mask for door area */ /* (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!) */ SetBackgroundBitmap(NULL, REDRAW_ALL); /* !!! FIX THIS !!! */ SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1); } /* ========================================================================= */ /* video functions */ /* ========================================================================= */ inline static int GetRealDepth(int depth) { return (depth == DEFAULT_DEPTH ? video.default_depth : depth); } inline static void sysFillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { #if defined(TARGET_SDL) SDLFillRectangle(bitmap, x, y, width, height, color); #else X11FillRectangle(bitmap, x, y, width, height, color); #endif } inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y, int mask_mode) { #if defined(TARGET_SDL) SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, mask_mode); #else X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, mask_mode); #endif } void InitVideoDisplay(void) { #if defined(TARGET_SDL) SDLInitVideoDisplay(); #else X11InitVideoDisplay(); #endif } void CloseVideoDisplay(void) { KeyboardAutoRepeatOn(); #if defined(TARGET_SDL) SDL_QuitSubSystem(SDL_INIT_VIDEO); #else if (display) XCloseDisplay(display); #endif } void InitVideoBuffer(int width, int height, int depth, boolean fullscreen) { video.width = width; video.height = height; video.depth = GetRealDepth(depth); video.fullscreen_available = FULLSCREEN_STATUS; video.fullscreen_enabled = FALSE; video.fullscreen_modes = NULL; video.fullscreen_mode_current = NULL; #if defined(TARGET_SDL) SDLInitVideoBuffer(&backbuffer, &window, fullscreen); #else X11InitVideoBuffer(&backbuffer, &window); #endif drawto = backbuffer; } Bitmap *CreateBitmapStruct(void) { #if defined(TARGET_SDL) return checked_calloc(sizeof(struct SDLSurfaceInfo)); #else return checked_calloc(sizeof(struct X11DrawableInfo)); #endif } Bitmap *CreateBitmap(int width, int height, int depth) { Bitmap *new_bitmap = CreateBitmapStruct(); int real_depth = GetRealDepth(depth); #if defined(TARGET_SDL) SDLCreateBitmapContent(new_bitmap, width, height, real_depth); #else X11CreateBitmapContent(new_bitmap, width, height, real_depth); #endif new_bitmap->width = width; new_bitmap->height = height; return new_bitmap; } inline static void FreeBitmapPointers(Bitmap *bitmap) { if (bitmap == NULL) return; #if defined(TARGET_SDL) SDLFreeBitmapPointers(bitmap); #else X11FreeBitmapPointers(bitmap); #endif checked_free(bitmap->source_filename); bitmap->source_filename = NULL; } inline static void TransferBitmapPointers(Bitmap *src_bitmap, Bitmap *dst_bitmap) { if (src_bitmap == NULL || dst_bitmap == NULL) return; FreeBitmapPointers(dst_bitmap); *dst_bitmap = *src_bitmap; } void FreeBitmap(Bitmap *bitmap) { if (bitmap == NULL) return; FreeBitmapPointers(bitmap); free(bitmap); } void CloseWindow(DrawWindow *window) { #if defined(TARGET_X11) if (window->drawable) { XUnmapWindow(display, window->drawable); XDestroyWindow(display, window->drawable); } if (window->gc) XFreeGC(display, window->gc); #endif } inline static boolean CheckDrawingArea(int x, int y, int width, int height, int draw_mask) { if (draw_mask == REDRAW_NONE) return FALSE; if (draw_mask & REDRAW_ALL) return TRUE; if ((draw_mask & REDRAW_FIELD) && x >= gfx.real_sx && x < gfx.real_sx + gfx.full_sxsize) return TRUE; if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize) return TRUE; if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy) return TRUE; return FALSE; } boolean DrawingDeactivated(int x, int y, int width, int height) { return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask); } boolean DrawingOnBackground(int x, int y) { return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) && CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask)); } void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingDeactivated(dst_x, dst_y, width, height)) return; sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_OPAQUE); } void FadeRectangle(Bitmap *bitmap_cross, int x, int y, int width, int height, int fade_mode, int fade_delay, int post_delay, void (*draw_border_function)(void)) { #if defined(TARGET_SDL) SDLFadeRectangle(bitmap_cross, x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); #else X11FadeRectangle(bitmap_cross, x, y, width, height, fade_mode, fade_delay, post_delay, draw_border_function); #endif } void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height, Pixel color) { if (DrawingDeactivated(x, y, width, height)) return; sysFillRectangle(bitmap, x, y, width, height, color); } void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height) { FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL); } void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y, int width, int height) { if (DrawingOnBackground(x, y)) BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y); else ClearRectangle(bitmap, x, y, width, height); } void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap) { #if defined(TARGET_X11) if (clip_gc) { bitmap->clip_gc = clip_gc; XSetClipMask(display, bitmap->clip_gc, clip_pixmap); } #endif } void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y) { #if defined(TARGET_X11) if (clip_gc) { bitmap->clip_gc = clip_gc; XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y); } #endif } void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingDeactivated(dst_x, dst_y, width, height)) return; sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y, BLIT_MASKED); } void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { if (DrawingOnBackground(dst_x, dst_y)) { /* draw background */ BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height, dst_x, dst_y); /* draw foreground */ SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc, dst_x - src_x, dst_y - src_y); BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } else BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height, dst_x, dst_y); } void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { #if defined(TARGET_SDL) SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL); #else X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL); #endif } void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y) { #if defined(TARGET_SDL) SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL); #else X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL); #endif } #if !defined(TARGET_X11_NATIVE) void DrawLine(Bitmap *bitmap, int from_x, int from_y, int to_x, int to_y, Pixel pixel, int line_width) { int x, y; for (x = 0; x < line_width; x++) { for (y = 0; y < line_width; y++) { int dx = x - line_width / 2; int dy = y - line_width / 2; if ((x == 0 && y == 0) || (x == 0 && y == line_width - 1) || (x == line_width - 1 && y == 0) || (x == line_width - 1 && y == line_width - 1)) continue; #if defined(TARGET_SDL) SDLDrawLine(bitmap, from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel); #elif defined(TARGET_ALLEGRO) AllegroDrawLine(bitmap->drawable, from_x + dx, from_y + dy, to_x + dx, to_y + dy, pixel); #endif } } } #endif void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel) { #if !defined(TARGET_X11_NATIVE) int line_width = 4; int i; for (i = 0; i < num_points - 1; i++) DrawLine(bitmap, points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, pixel, line_width); /* SDLDrawLines(bitmap->surface, points, num_points, pixel); */ #else XSetForeground(display, bitmap->line_gc[1], pixel); XDrawLines(display, bitmap->drawable, bitmap->line_gc[1], (XPoint *)points, num_points, CoordModeOrigin); #endif } Pixel GetPixel(Bitmap *bitmap, int x, int y) { if (x < 0 || x >= bitmap->width || y < 0 || y >= bitmap->height) return BLACK_PIXEL; #if defined(TARGET_SDL) return SDLGetPixel(bitmap, x, y); #elif defined(TARGET_ALLEGRO) return AllegroGetPixel(bitmap->drawable, x, y); #else return X11GetPixel(bitmap, x, y); #endif } Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r, unsigned int color_g, unsigned int color_b) { #if defined(TARGET_SDL) return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b); #elif defined(TARGET_ALLEGRO) return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8); #else return X11GetPixelFromRGB(color_r, color_g, color_b); #endif } Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color) { unsigned int color_r = (color >> 16) & 0xff; unsigned int color_g = (color >> 8) & 0xff; unsigned int color_b = (color >> 0) & 0xff; return GetPixelFromRGB(bitmap, color_r, color_g, color_b); } /* execute all pending screen drawing operations */ void FlushDisplay(void) { #ifndef TARGET_SDL XFlush(display); #endif } /* execute and wait for all pending screen drawing operations */ void SyncDisplay(void) { #ifndef TARGET_SDL XSync(display, FALSE); #endif } void KeyboardAutoRepeatOn(void) { #if defined(TARGET_SDL) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2, SDL_DEFAULT_REPEAT_INTERVAL / 2); SDL_EnableUNICODE(1); #else if (display) XAutoRepeatOn(display); #endif } void KeyboardAutoRepeatOff(void) { #if defined(TARGET_SDL) SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL); SDL_EnableUNICODE(0); #else if (display) XAutoRepeatOff(display); #endif } boolean PointerInWindow(DrawWindow *window) { #if defined(TARGET_SDL) return TRUE; #else Window root, child; int root_x, root_y; unsigned int mask; int win_x, win_y; /* if XQueryPointer() returns False, the pointer is not on the same screen as the specified window */ return XQueryPointer(display, window->drawable, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask); #endif } boolean SetVideoMode(boolean fullscreen) { #if defined(TARGET_SDL) return SDLSetVideoMode(&backbuffer, fullscreen); #else boolean success = TRUE; if (fullscreen && video.fullscreen_available) { Error(ERR_WARN, "fullscreen not available in X11 version"); /* display error message only once */ video.fullscreen_available = FALSE; success = FALSE; } return success; #endif } boolean ChangeVideoModeIfNeeded(boolean fullscreen) { #if defined(TARGET_SDL) if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)|| (!fullscreen && video.fullscreen_enabled)) fullscreen = SetVideoMode(fullscreen); #endif return fullscreen; } Bitmap *LoadImage(char *filename) { Bitmap *new_bitmap; #if defined(TARGET_SDL) new_bitmap = SDLLoadImage(filename); #else new_bitmap = X11LoadImage(filename); #endif if (new_bitmap) new_bitmap->source_filename = getStringCopy(filename); return new_bitmap; } Bitmap *LoadCustomImage(char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) Error(ERR_EXIT, "LoadCustomImage(): cannot find file '%s'", basename); if ((new_bitmap = LoadImage(filename)) == NULL) Error(ERR_EXIT, "LoadImage() failed: %s", GetError()); return new_bitmap; } void ReloadCustomImage(Bitmap *bitmap, char *basename) { char *filename = getCustomImageFilename(basename); Bitmap *new_bitmap; if (filename == NULL) /* (should never happen) */ { Error(ERR_WARN, "ReloadCustomImage(): cannot find file '%s'", basename); return; } if (strEqual(filename, bitmap->source_filename)) { /* The old and new image are the same (have the same filename and path). This usually means that this image does not exist in this graphic set and a fallback to the existing image is done. */ return; } if ((new_bitmap = LoadImage(filename)) == NULL) { Error(ERR_WARN, "LoadImage() failed: %s", GetError()); return; } if (bitmap->width != new_bitmap->width || bitmap->height != new_bitmap->height) { Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions", filename); FreeBitmap(new_bitmap); return; } TransferBitmapPointers(new_bitmap, bitmap); free(new_bitmap); } Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height) { Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH); #if defined(TARGET_SDL) SDLZoomBitmap(src_bitmap, dst_bitmap); #else X11ZoomBitmap(src_bitmap, dst_bitmap); #endif return dst_bitmap; } static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor, boolean create_small_bitmaps) { Bitmap swap_bitmap; Bitmap *new_bitmap; Bitmap *tmp_bitmap_1; Bitmap *tmp_bitmap_2; Bitmap *tmp_bitmap_4; Bitmap *tmp_bitmap_8; Bitmap *tmp_bitmap_16; Bitmap *tmp_bitmap_32; int width_1, height_1; int width_2, height_2; int width_4, height_4; int width_8, height_8; int width_16, height_16; int width_32, height_32; int new_width, new_height; /* calculate new image dimensions for normal sized image */ width_1 = old_bitmap->width * zoom_factor; height_1 = old_bitmap->height * zoom_factor; /* get image with normal size (this might require scaling up) */ if (zoom_factor != 1) tmp_bitmap_1 = ZoomBitmap(old_bitmap, width_1, height_1); else tmp_bitmap_1 = old_bitmap; /* this is only needed to make compilers happy */ tmp_bitmap_2 = NULL; tmp_bitmap_4 = NULL; tmp_bitmap_8 = NULL; tmp_bitmap_16 = NULL; tmp_bitmap_32 = NULL; if (create_small_bitmaps) { /* calculate new image dimensions for small images */ width_2 = width_1 / 2; height_2 = height_1 / 2; width_4 = width_1 / 4; height_4 = height_1 / 4; width_8 = width_1 / 8; height_8 = height_1 / 8; width_16 = width_1 / 16; height_16 = height_1 / 16; width_32 = width_1 / 32; height_32 = height_1 / 32; UPDATE_BUSY_STATE(); /* get image with 1/2 of normal size (for use in the level editor) */ if (zoom_factor != 2) tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2); else tmp_bitmap_2 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/4 of normal size (for use in the level editor) */ if (zoom_factor != 4) tmp_bitmap_4 = ZoomBitmap(tmp_bitmap_2, width_2 / 2, height_2 / 2); else tmp_bitmap_4 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/8 of normal size (for use on the preview screen) */ if (zoom_factor != 8) tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_4, width_4 / 2, height_4 / 2); else tmp_bitmap_8 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/16 of normal size (for use on the preview screen) */ if (zoom_factor != 16) tmp_bitmap_16 = ZoomBitmap(tmp_bitmap_8, width_8 / 2, height_8 / 2); else tmp_bitmap_16 = old_bitmap; UPDATE_BUSY_STATE(); /* get image with 1/32 of normal size (for use on the preview screen) */ if (zoom_factor != 32) tmp_bitmap_32 = ZoomBitmap(tmp_bitmap_16, width_16 / 2, height_16 / 2); else tmp_bitmap_32 = old_bitmap; UPDATE_BUSY_STATE(); } #if 0 /* if image was scaled up, create new clipmask for normal size image */ if (zoom_factor != 1) { #if defined(TARGET_X11) if (old_bitmap->clip_mask) XFreePixmap(display, old_bitmap->clip_mask); old_bitmap->clip_mask = Pixmap_to_Mask(tmp_bitmap_1->drawable, width_1, height_1); XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask); #else SDL_Surface *tmp_surface_1 = tmp_bitmap_1->surface; if (old_bitmap->surface_masked) SDL_FreeSurface(old_bitmap->surface_masked); SDL_SetColorKey(tmp_surface_1, SDL_SRCCOLORKEY, SDL_MapRGB(tmp_surface_1->format, 0x00, 0x00, 0x00)); if ((old_bitmap->surface_masked = SDL_DisplayFormat(tmp_surface_1)) ==NULL) Error(ERR_EXIT, "SDL_DisplayFormat() failed"); SDL_SetColorKey(tmp_surface_1, 0, 0); /* reset transparent pixel */ #endif } #endif if (create_small_bitmaps) { new_width = width_1; new_height = height_1 + (height_1 + 1) / 2; /* prevent odd height */ new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH); BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0); BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2, 0, height_1); BlitBitmap(tmp_bitmap_4, new_bitmap, 0, 0, width_1 / 4, height_1 / 4, width_1 / 2, height_1); BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8, 3 * width_1 / 4, height_1); BlitBitmap(tmp_bitmap_16, new_bitmap, 0, 0, width_1 / 16, height_1 / 16, 7 * width_1 / 8, height_1); BlitBitmap(tmp_bitmap_32, new_bitmap, 0, 0, width_1 / 32, height_1 / 32, 15 * width_1 / 16, height_1); UPDATE_BUSY_STATE(); } else { new_width = width_1; new_height = height_1; new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */ } if (create_small_bitmaps) { /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */ if (zoom_factor != 1) FreeBitmap(tmp_bitmap_1); if (zoom_factor != 2) FreeBitmap(tmp_bitmap_2); if (zoom_factor != 4) FreeBitmap(tmp_bitmap_4); if (zoom_factor != 8) FreeBitmap(tmp_bitmap_8); if (zoom_factor != 16) FreeBitmap(tmp_bitmap_16); if (zoom_factor != 32) FreeBitmap(tmp_bitmap_32); } /* replace image with extended image (containing 1/1, 1/2, 1/4, 1/8 size) */ #if defined(TARGET_SDL) swap_bitmap.surface = old_bitmap->surface; old_bitmap->surface = new_bitmap->surface; new_bitmap->surface = swap_bitmap.surface; #else swap_bitmap.drawable = old_bitmap->drawable; old_bitmap->drawable = new_bitmap->drawable; new_bitmap->drawable = swap_bitmap.drawable; #endif old_bitmap->width = new_bitmap->width; old_bitmap->height = new_bitmap->height; #if 1 /* this replaces all blit masks created when loading -- maybe optimize this */ { #if defined(TARGET_X11) if (old_bitmap->clip_mask) XFreePixmap(display, old_bitmap->clip_mask); old_bitmap->clip_mask = Pixmap_to_Mask(old_bitmap->drawable, new_width, new_height); XSetClipMask(display, old_bitmap->stored_clip_gc, old_bitmap->clip_mask); #else SDL_Surface *old_surface = old_bitmap->surface; if (old_bitmap->surface_masked) SDL_FreeSurface(old_bitmap->surface_masked); SDL_SetColorKey(old_surface, SDL_SRCCOLORKEY, SDL_MapRGB(old_surface->format, 0x00, 0x00, 0x00)); if ((old_bitmap->surface_masked = SDL_DisplayFormat(old_surface)) ==NULL) Error(ERR_EXIT, "SDL_DisplayFormat() failed"); SDL_SetColorKey(old_surface, 0, 0); /* reset transparent pixel */ #endif } #endif UPDATE_BUSY_STATE(); FreeBitmap(new_bitmap); /* this actually frees the _old_ bitmap now */ } void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor) { CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE); } void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor) { CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE); } /* ------------------------------------------------------------------------- */ /* mouse pointer functions */ /* ------------------------------------------------------------------------- */ #if !defined(PLATFORM_MSDOS) #define USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER 0 /* XPM image definitions */ static const char *cursor_image_none[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "0,0" }; #if USE_ONE_PIXEL_PLAYFIELD_MOUSEPOINTER static const char *cursor_image_dot[] = { /* width height num_colors chars_per_pixel */ " 16 16 3 1", /* colors */ "X c #000000", ". c #ffffff", " c None", /* pixels */ " X ", "X.X ", " X ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", /* hot spot */ "1,1" }; static const char **cursor_image_playfield = cursor_image_dot; #else /* some people complained about a "white dot" on the screen and thought it was a graphical error... OK, let's just remove the whole pointer :-) */ static const char **cursor_image_playfield = cursor_image_none; #endif #if defined(TARGET_SDL) static const int cursor_bit_order = BIT_ORDER_MSB; #elif defined(TARGET_X11_NATIVE) static const int cursor_bit_order = BIT_ORDER_LSB; #endif static struct MouseCursorInfo *get_cursor_from_image(const char **image) { struct MouseCursorInfo *cursor; boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB); int header_lines = 4; int x, y, i; cursor = checked_calloc(sizeof(struct MouseCursorInfo)); sscanf(image[0], " %d %d ", &cursor->width, &cursor->height); i = -1; for (y = 0; y < cursor->width; y++) { for (x = 0; x < cursor->height; x++) { int bit_nr = x % 8; int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr ); if (bit_nr == 0) { i++; cursor->data[i] = cursor->mask[i] = 0; } switch (image[header_lines + y][x]) { case 'X': cursor->data[i] |= bit_mask; cursor->mask[i] |= bit_mask; break; case '.': cursor->mask[i] |= bit_mask; break; case ' ': break; } } } sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y); return cursor; } #endif /* !PLATFORM_MSDOS */ void SetMouseCursor(int mode) { #if !defined(PLATFORM_MSDOS) static struct MouseCursorInfo *cursor_none = NULL; static struct MouseCursorInfo *cursor_playfield = NULL; struct MouseCursorInfo *cursor_new; if (cursor_none == NULL) cursor_none = get_cursor_from_image(cursor_image_none); if (cursor_playfield == NULL) cursor_playfield = get_cursor_from_image(cursor_image_playfield); cursor_new = (mode == CURSOR_DEFAULT ? NULL : mode == CURSOR_NONE ? cursor_none : mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL); #if defined(TARGET_SDL) SDLSetMouseCursor(cursor_new); #elif defined(TARGET_X11_NATIVE) X11SetMouseCursor(cursor_new); #endif #endif } /* ========================================================================= */ /* audio functions */ /* ========================================================================= */ void OpenAudio(void) { /* always start with reliable default values */ audio.sound_available = FALSE; audio.music_available = FALSE; audio.loops_available = FALSE; audio.sound_enabled = FALSE; audio.sound_deactivated = FALSE; audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0; audio.mixer_pid = 0; audio.device_name = NULL; audio.device_fd = -1; audio.num_channels = 0; audio.music_channel = 0; audio.first_sound_channel = 0; #if defined(TARGET_SDL) SDLOpenAudio(); #elif defined(PLATFORM_UNIX) UnixOpenAudio(); #elif defined(PLATFORM_MSDOS) MSDOSOpenAudio(); #endif } void CloseAudio(void) { #if defined(TARGET_SDL) SDLCloseAudio(); #elif defined(PLATFORM_UNIX) UnixCloseAudio(); #elif defined(PLATFORM_MSDOS) MSDOSCloseAudio(); #endif audio.sound_enabled = FALSE; } void SetAudioMode(boolean enabled) { if (!audio.sound_available) return; audio.sound_enabled = enabled; } /* ========================================================================= */ /* event functions */ /* ========================================================================= */ void InitEventFilter(EventFilter filter_function) { #if defined(TARGET_SDL) /* set event filter to filter out certain events */ SDL_SetEventFilter(filter_function); #endif } boolean PendingEvent(void) { #if defined(TARGET_SDL) return (SDL_PollEvent(NULL) ? TRUE : FALSE); #else return (XPending(display) ? TRUE : FALSE); #endif } void NextEvent(Event *event) { #if defined(TARGET_SDL) SDLNextEvent(event); #else XNextEvent(display, event); #endif } void PeekEvent(Event *event) { #if defined(TARGET_SDL) SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS); #else XPeekEvent(display, event); #endif } Key GetEventKey(KeyEvent *event, boolean with_modifiers) { #if defined(TARGET_SDL) #if 0 printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n", (int)event->keysym.unicode, (int)event->keysym.sym, (int)SDL_GetModState()); #endif if (with_modifiers && event->keysym.unicode > 0x0000 && event->keysym.unicode < 0x2000) return event->keysym.unicode; else return event->keysym.sym; #else #if 0 printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n", (int)XLookupKeysym(event, event->state), (int)XLookupKeysym(event, 0)); #endif if (with_modifiers) return XLookupKeysym(event, event->state); else return XLookupKeysym(event, 0); #endif } KeyMod HandleKeyModState(Key key, int key_status) { static KeyMod current_modifiers = KMOD_None; if (key != KSYM_UNDEFINED) /* new key => check for modifier key change */ { KeyMod new_modifier = KMOD_None; switch(key) { case KSYM_Shift_L: new_modifier = KMOD_Shift_L; break; case KSYM_Shift_R: new_modifier = KMOD_Shift_R; break; case KSYM_Control_L: new_modifier = KMOD_Control_L; break; case KSYM_Control_R: new_modifier = KMOD_Control_R; break; case KSYM_Meta_L: new_modifier = KMOD_Meta_L; break; case KSYM_Meta_R: new_modifier = KMOD_Meta_R; break; case KSYM_Alt_L: new_modifier = KMOD_Alt_L; break; case KSYM_Alt_R: new_modifier = KMOD_Alt_R; break; default: break; } if (key_status == KEY_PRESSED) current_modifiers |= new_modifier; else current_modifiers &= ~new_modifier; } return current_modifiers; } KeyMod GetKeyModState() { #if defined(TARGET_SDL) return (KeyMod)SDL_GetModState(); #else return HandleKeyModState(KSYM_UNDEFINED, 0); #endif } KeyMod GetKeyModStateFromEvents() { /* always use key modifier state as tracked from key events (this is needed if the modifier key event was injected into the event queue, but the key was not really pressed on keyboard -- SDL_GetModState() seems to directly query the keys as held pressed on the keyboard) -- this case is currently only used to filter out clipboard insert events from "True X-Mouse" tool */ return HandleKeyModState(KSYM_UNDEFINED, 0); } boolean CheckCloseWindowEvent(ClientMessageEvent *event) { if (event->type != EVENT_CLIENTMESSAGE) return FALSE; #if defined(TARGET_SDL) return TRUE; /* the only possible message here is SDL_QUIT */ #elif defined(PLATFORM_UNIX) if ((event->window == window->drawable) && (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE))) return TRUE; #endif return FALSE; } /* ========================================================================= */ /* joystick functions */ /* ========================================================================= */ void InitJoysticks() { int i; #if defined(NO_JOYSTICK) return; /* joysticks generally deactivated by compile-time directive */ #endif /* always start with reliable default values */ joystick.status = JOYSTICK_NOT_AVAILABLE; for (i = 0; i < MAX_PLAYERS; i++) joystick.fd[i] = -1; /* joystick device closed */ #if defined(TARGET_SDL) SDLInitJoysticks(); #elif defined(PLATFORM_UNIX) UnixInitJoysticks(); #elif defined(PLATFORM_MSDOS) MSDOSInitJoysticks(); #endif #if 0 for (i = 0; i < MAX_PLAYERS; i++) printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]); #endif } boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2) { #if defined(TARGET_SDL) return SDLReadJoystick(nr, x, y, b1, b2); #elif defined(PLATFORM_UNIX) return UnixReadJoystick(nr, x, y, b1, b2); #elif defined(PLATFORM_MSDOS) return MSDOSReadJoystick(nr, x, y, b1, b2); #endif }