/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Video driver using the VBE/AF 2.0 hardware accelerator API, * plus extensions added by the FreeBE/AF project. * * This driver provides accelerated support for: * * - scanline fills (solid, XOR, and patterned) * - area fills (solid, XOR, and patterned) * - line drawing (solid and XOR) * - triangle drawing (solid and XOR) * - monochrome character expansion * - blitting within the video memory * - masked blitting within the video memory * - blits from system memory * - masked blits from system memory * - hardware mouse cursors * * The FreeBE/AF project (http://www.talula.demon.co.uk/freebe/) * has defined a number of API extensions, of which this driver * implements: * * FAFEXT_INIT - extension init and new driver relocation mechanism * FAFEXT_HWPTR - farptr access to video memory (no more Fat DS hack) * FAFEXT_LIBC - exports a bunch of callback functions from libc * FAFEXT_PMODE - exports the SciTech pmode API callback functions * * On the subject of VBE/AF in general: * * Kendall Bennett and Tom Ryan of SciTech software deserve * significant thanks for coming up with such a magnificent API and * then helping me write this driver, after the VESA people (may they * be smitten with plagues of locusts and then develop subtle memory * leaks in their code :-) decided to charge stupid sums of money for * copies of the /AF specification. Unfortunately, SciTech have * subsequently abandoned VBE/AF in favour of a closed, proprietary * system called Nucleus. Ah well, I'm sure that this makes sense * for them in commercial terms, even if it is something of a * disappointment for us idealistic hacker types... * * The problem with Nucleus is that the spec is only available under * NDA, so I cannot support it directly in Allegro. The plan, * therefore, is to write a Nucleus to VBE/AF wrapper driver. * This requires a few callback routines that stock VBE/AF doesn't * provide, hence the Nucleus-specific extensions in this file. It * doesn't provide direct Nucleus support, but hopefully will enable * someone (whether us or SciTech) to add that support in the future * via an external driver binary. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include "allegro.h" #if (defined ALLEGRO_DOS) || (defined ALLEGRO_LINUX_VBEAF) #include "allegro/internal/aintern.h" #ifdef ALLEGRO_INTERNAL_HEADER #include ALLEGRO_INTERNAL_HEADER #endif #if (defined ALLEGRO_DJGPP) && (!defined SCAN_DEPEND) #include #include #include #endif /* main driver routines */ static BITMAP *vbeaf_init(int w, int h, int v_w, int v_h, int color_depth); static void vbeaf_exit(BITMAP *b); static void vbeaf_save(void); static void vbeaf_restore(void); static GFX_MODE_LIST *vbeaf_fetch_mode_list(void); static void vbeaf_vsync(void); static int vbeaf_scroll(int x, int y); static void vbeaf_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync); static int vbeaf_request_scroll(int x, int y); static int vbeaf_poll_scroll(void); static int vbeaf_set_mouse_sprite(BITMAP *sprite, int xfocus, int yfocus); static int vbeaf_show_mouse(BITMAP *bmp, int x, int y); static void vbeaf_hide_mouse(void); static void vbeaf_move_mouse(int x, int y); static void vbeaf_drawing_mode(void); static int vbeaf_locate_driver(void); static int vbeaf_lowlevel_init(void); /* accelerated drawing functions */ static void vbeaf_hline(BITMAP *bmp, int x1, int y, int x2, int color); static void vbeaf_vline_a(BITMAP *bmp, int x, int y1, int y2, int color); static void vbeaf_vline_b(BITMAP *bmp, int x, int y1, int y2, int color); static void vbeaf_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color); static void vbeaf_rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color); static void vbeaf_triangle(BITMAP *bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color); static void vbeaf_draw_glyph(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg); static void vbeaf_draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y); static void vbeaf_blit_from_memory(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); static void vbeaf_blit_to_self(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); static void vbeaf_masked_blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); static void vbeaf_clear_to_color(BITMAP *bitmap, int color); #ifdef ALLEGRO_DOS static void vbeaf_move_mouse_end(void); static void vbeaf_draw_sprite_end(void); static void vbeaf_blit_from_memory_end(void); #endif /* original software drawing functions */ static void (*orig_vline)(BITMAP *bmp, int x, int y1, int y2, int color); static void (*orig_hline)(BITMAP *bmp, int x1, int y, int x2, int color); static void (*orig_line)(BITMAP *bmp, int x1, int y1, int x2, int y2, int color); static void (*orig_rectfill)(BITMAP *bmp, int x1, int y1, int x2, int y2, int color); static void (*orig_draw_glyph)(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg); static void (*orig_draw_sprite)(BITMAP *bmp, BITMAP *sprite, int x, int y); static void (*orig_masked_blit)(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height); static char vbeaf_desc[256] = EMPTY_STRING; /* the video driver structure */ GFX_DRIVER gfx_vbeaf = { GFX_VBEAF, empty_string, empty_string, "VBE/AF", vbeaf_init, vbeaf_exit, vbeaf_scroll, vbeaf_vsync, vbeaf_set_palette_range, vbeaf_request_scroll, vbeaf_poll_scroll, NULL, /* enable triple buffer */ NULL, NULL, NULL, NULL, /* no video bitmaps */ NULL, NULL, /* no system bitmaps */ NULL, NULL, NULL, NULL, /* no hardware cursor (yet) */ NULL, /* no drawing mode hook */ vbeaf_save, vbeaf_restore, NULL, /* AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a)); */ vbeaf_fetch_mode_list, /* fetch mode hook */ 0, 0, FALSE, 0, 0, 0, 0, FALSE }; typedef struct AF_FIX_POINT /* fixed point coordinate pair */ { fixed x; fixed y; } AF_FIX_POINT; typedef struct AF_TRAP /* trapezium information block */ { long y; long count; fixed x1; fixed x2; fixed slope1; fixed slope2; } AF_TRAP; typedef struct AF_CURSOR /* hardware cursor description */ { unsigned long xorMask[32]; unsigned long andMask[32]; unsigned long hotx; unsigned long hoty; } AF_CURSOR; typedef struct AF_PALETTE /* color value (not in Allegro order) */ { unsigned char blue; unsigned char green; unsigned char red; unsigned char alpha; } AF_PALETTE; #ifdef ALLEGRO_GCC #define __PACKED__ __attribute__ ((packed)) #else #define __PACKED__ #endif #ifdef ALLEGRO_WATCOM #pragma pack (1) #endif typedef struct AF_MODE_INFO /* mode information structure */ { unsigned short Attributes __PACKED__; unsigned short XResolution __PACKED__; unsigned short YResolution __PACKED__; unsigned short BytesPerScanLine __PACKED__; unsigned short BitsPerPixel __PACKED__; unsigned short MaxBuffers __PACKED__; unsigned char RedMaskSize __PACKED__; unsigned char RedFieldPosition __PACKED__; unsigned char GreenMaskSize __PACKED__; unsigned char GreenFieldPosition __PACKED__; unsigned char BlueMaskSize __PACKED__; unsigned char BlueFieldPosition __PACKED__; unsigned char RsvdMaskSize __PACKED__; unsigned char RsvdFieldPosition __PACKED__; unsigned short MaxBytesPerScanLine __PACKED__; unsigned short MaxScanLineWidth __PACKED__; /* VBE/AF 2.0 extensions */ unsigned short LinBytesPerScanLine __PACKED__; unsigned char BnkMaxBuffers __PACKED__; unsigned char LinMaxBuffers __PACKED__; unsigned char LinRedMaskSize __PACKED__; unsigned char LinRedFieldPosition __PACKED__; unsigned char LinGreenMaskSize __PACKED__; unsigned char LinGreenFieldPosition __PACKED__; unsigned char LinBlueMaskSize __PACKED__; unsigned char LinBlueFieldPosition __PACKED__; unsigned char LinRsvdMaskSize __PACKED__; unsigned char LinRsvdFieldPosition __PACKED__; unsigned long MaxPixelClock __PACKED__; unsigned long VideoCapabilities __PACKED__; unsigned short VideoMinXScale __PACKED__; unsigned short VideoMinYScale __PACKED__; unsigned short VideoMaxXScale __PACKED__; unsigned short VideoMaxYScale __PACKED__; unsigned char reserved[76] __PACKED__; } AF_MODE_INFO; #define DC struct AF_DRIVER *dc typedef struct AF_DRIVER /* VBE/AF driver structure */ { /* driver header */ char Signature[12] __PACKED__; unsigned long Version __PACKED__; unsigned long DriverRev __PACKED__; char OemVendorName[80] __PACKED__; char OemCopyright[80] __PACKED__; unsigned short *AvailableModes __PACKED__; unsigned long TotalMemory __PACKED__; unsigned long Attributes __PACKED__; unsigned long BankSize __PACKED__; unsigned long BankedBasePtr __PACKED__; unsigned long LinearSize __PACKED__; unsigned long LinearBasePtr __PACKED__; unsigned long LinearGranularity __PACKED__; unsigned short *IOPortsTable __PACKED__; unsigned long IOMemoryBase[4] __PACKED__; unsigned long IOMemoryLen[4] __PACKED__; unsigned long LinearStridePad __PACKED__; unsigned short PCIVendorID __PACKED__; unsigned short PCIDeviceID __PACKED__; unsigned short PCISubSysVendorID __PACKED__; unsigned short PCISubSysID __PACKED__; unsigned long Checksum __PACKED__; unsigned long res2[6] __PACKED__; /* near pointers mapped by the application */ void *IOMemMaps[4] __PACKED__; void *BankedMem __PACKED__; void *LinearMem __PACKED__; unsigned long res3[5] __PACKED__; /* driver state variables */ unsigned long BufferEndX __PACKED__; unsigned long BufferEndY __PACKED__; unsigned long OriginOffset __PACKED__; unsigned long OffscreenOffset __PACKED__; unsigned long OffscreenStartY __PACKED__; unsigned long OffscreenEndY __PACKED__; unsigned long res4[10] __PACKED__; /* relocatable 32 bit bank switch routine, for Windows (ugh!) */ unsigned long SetBank32Len __PACKED__; void *SetBank32 __PACKED__; /* callback functions provided by the application */ void *Int86 __PACKED__; void *CallRealMode __PACKED__; /* main driver setup routine */ void *InitDriver __PACKED__; /* VBE/AF 1.0 asm interface (obsolete and not supported by Allegro) */ void *af10Funcs[40] __PACKED__; /* VBE/AF 2.0 extensions */ void *PlugAndPlayInit __PACKED__; /* FreeBE/AF extension query function */ void *(*OemExt)(DC, unsigned long id); /* extension hook for implementing additional VESA interfaces */ void *SupplementalExt __PACKED__; /* device driver functions */ long (*GetVideoModeInfo)(DC, short mode, AF_MODE_INFO *modeInfo); long (*SetVideoMode)(DC, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, void *crtc); void (*RestoreTextMode)(DC); long (*GetClosestPixelClock)(DC, short mode, unsigned long pixelClock); void (*SaveRestoreState)(DC, int subfunc, void *saveBuf); void (*SetDisplayStart)(DC, long x, long y, long waitVRT); void (*SetActiveBuffer)(DC, long index); void (*SetVisibleBuffer)(DC, long index, long waitVRT); int (*GetDisplayStartStatus)(DC); void (*EnableStereoMode)(DC, int enable); void (*SetPaletteData)(DC, AF_PALETTE *pal, long num, long index, long waitVRT); void (*SetGammaCorrectData)(DC, AF_PALETTE *pal, long num, long index); void (*SetBank)(DC, long bank); /* hardware cursor functions */ void (*SetCursor)(DC, AF_CURSOR *cursor); void (*SetCursorPos)(DC, long x, long y); void (*SetCursorColor)(DC, unsigned char red, unsigned char green, unsigned char blue); void (*ShowCursor)(DC, long visible); /* 2D rendering functions */ void (*WaitTillIdle)(DC); void (*EnableDirectAccess)(DC); void (*DisableDirectAccess)(DC); void (*SetMix)(DC, long foreMix, long backMix); void (*Set8x8MonoPattern)(DC, unsigned char *pattern); void (*Set8x8ColorPattern)(DC, int index, unsigned long *pattern); void (*Use8x8ColorPattern)(DC, int index); void (*SetLineStipple)(DC, unsigned short stipple); void (*SetLineStippleCount)(DC, unsigned long count); void (*SetClipRect)(DC, long minx, long miny, long maxx, long maxy); void (*DrawScan)(DC, long color, long y, long x1, long x2); void (*DrawPattScan)(DC, long foreColor, long backColor, long y, long x1, long x2); void (*DrawColorPattScan)(DC, long y, long x1, long x2); void (*DrawScanList)(DC, unsigned long color, long y, long length, short *scans); void (*DrawPattScanList)(DC, unsigned long foreColor, unsigned long backColor, long y, long length, short *scans); void (*DrawColorPattScanList)(DC, long y, long length, short *scans); void (*DrawRect)(DC, unsigned long color, long left, long top, long width, long height); void (*DrawPattRect)(DC, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height); void (*DrawColorPattRect)(DC, long left, long top, long width, long height); void (*DrawLine)(DC, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2); void (*DrawStippleLine)(DC, unsigned long foreColor, unsigned long backColor, fixed x1, fixed y1, fixed x2, fixed y2); void (*DrawTrap)(DC, unsigned long color, AF_TRAP *trap); void (*DrawTri)(DC, unsigned long color, AF_FIX_POINT *v1, AF_FIX_POINT *v2, AF_FIX_POINT *v3, fixed xOffset, fixed yOffset); void (*DrawQuad)(DC, unsigned long color, AF_FIX_POINT *v1, AF_FIX_POINT *v2, AF_FIX_POINT *v3, AF_FIX_POINT *v4, fixed xOffset, fixed yOffset); void (*PutMonoImage)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, unsigned char *image); void (*PutMonoImageLin)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imageOfs); void (*PutMonoImageBM)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imagePhysAddr); void (*BitBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op); void (*BitBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op); void (*BitBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op); void (*BitBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op); void (*SrcTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*SrcTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*SrcTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*SrcTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*DstTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*DstTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*DstTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*DstTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent); void (*StretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op); void (*StretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op); void (*StretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op); void (*StretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op); void (*SrcTransStretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*SrcTransStretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*SrcTransStretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*SrcTransStretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*DstTransStretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*DstTransStretchBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*DstTransStretchBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); void (*DstTransStretchBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op, unsigned long transparent); /* hardware video functions */ void (*SetVideoInput)(DC, long width, long height, long format); void *(*SetVideoOutput)(DC, long left, long top, long width, long height); void (*StartVideoFrame)(DC); void (*EndVideoFrame)(DC); } AF_DRIVER; #undef DC /* FreeBE/AF API extensions use 32 bit magic numbers */ #define FAF_ID(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d) /* ID code and magic return value for initialising the extensions */ #define FAFEXT_INIT FAF_ID('I','N','I','T') #define FAFEXT_MAGIC FAF_ID('E','X', 0, 0) /* function exporting extensions (needed for Nucleus compatibility) */ #define FAFEXT_LIBC FAF_ID('L','I','B','C') #define FAFEXT_PMODE FAF_ID('P','M','O','D') /* extension providing a hardware-specific way to access video memory */ #define FAFEXT_HWPTR FAF_ID('H','P','T','R') typedef struct FAF_HWPTR { int sel; unsigned long offset; } FAF_HWPTR; typedef struct FAF_HWPTR_DATA { FAF_HWPTR IOMemMaps[4]; FAF_HWPTR BankedMem; FAF_HWPTR LinearMem; } FAF_HWPTR_DATA; #ifdef ALLEGRO_LINUX #include #include /* quick and dirty Linux emulation of the DOS memory mapping routines */ #define _create_linear_mapping(_addr, _base, _len) \ ({ \ (_addr)->base = _base; \ (_addr)->size = _len; \ (_addr)->perms = PROT_READ | PROT_WRITE; \ __al_linux_map_memory(_addr); \ }) #define _remove_linear_mapping(_addr) \ { \ if ((_addr)->data) \ __al_linux_unmap_memory(_addr); \ } #define _create_selector(sel, addr, len) -1 #define _remove_selector(sel) #define MMAP struct MAPPED_MEMORY #define NOMM { 0, 0, 0, 0 } #define MVAL(a) a.data #else /* DOS version */ #define MMAP unsigned long #define NOMM 0 #define MVAL(a) (void *)((a)-__djgpp_base_address) #endif static AF_DRIVER *af_driver = NULL; /* the VBE/AF driver */ void *_accel_driver = NULL; /* externally visible driver pointer */ int _accel_active = FALSE; /* is the accelerator busy? */ void *_accel_set_bank; /* shortcuts to driver functions */ void *_accel_idle; static int in_af_mode = FALSE; /* true if VBE/AF is in use */ static int faf_id = FALSE; /* true if FreeBE/AF detected */ static int faf_ext = 0; /* FreeBE/AF extensions version */ static FAF_HWPTR_DATA *faf_farptr; /* FreeBE/AF farptr data */ static int vbeaf_xscroll = 0; /* current display start address */ static int vbeaf_yscroll = 0; static int vbeaf_fg_mix = 0; /* current hardware mix mode */ static int vbeaf_bg_mix = 0; static int vbeaf_cur_c1 = -1; /* hardware cursor colors */ static int vbeaf_cur_c2 = -1; static BITMAP *vbeaf_cur_bmp = NULL; /* bitmap showing the cursor */ static int vbeaf_cur_x; /* cursor position */ static int vbeaf_cur_y; static int vbeaf_cur_on; static BITMAP *vbeaf_pattern = NULL; /* currently loaded pattern bitmap */ static MMAP af_memmap[4] = { NOMM, NOMM, NOMM, NOMM }; static MMAP af_banked_mem = NOMM; static MMAP af_linear_mem = NOMM; #ifdef ALLEGRO_DOS static int vbeaf_nearptr = FALSE; /* did we enable nearptrs ourselves? */ #endif #ifdef ALLEGRO_LINUX int _vbeaf_selector = 0; /* Linux version of __djgpp_ds_alias */ #endif static int saved_mode; /* state info for console switches */ static int saved_vw; static int saved_vh; static int saved_wret; extern void _af_int86(void), _af_call_rm(void), _af_wrapper(void), _af_wrapper_end(void); #ifdef ALLEGRO_DJGPP /* djgpp wrapper to disable exceptions during critical operations */ #define SAFE_CALL(FUNC) \ { \ int _ds, _es, _ss; \ \ asm volatile ( \ " movw %%ds, %w0 ; " \ " movw %%es, %w1 ; " \ " movw %%ss, %w2 ; " \ " movw %w3, %%ds ; " \ " movw %w3, %%es ; " \ " movw %w3, %%ss ; " \ \ : "=&q" (_ds), \ "=&q" (_es), \ "=&q" (_ss) \ \ : "q" (__djgpp_ds_alias) \ ); \ \ FUNC \ \ asm volatile ( \ "movw %w0, %%ds ; " \ "movw %w1, %%es ; " \ "movw %w2, %%ss ; " \ : \ : "q" (_ds), \ "q" (_es), \ "q" (_ss) \ ); \ } #define SAFISH_CALL(FUNC) FUNC #elif defined ALLEGRO_LINUX /* Linux wrapper to disable console switches during critical operations */ #define SAFE_CALL(FUNC) \ { \ __al_linux_switching_blocked++; \ \ FUNC \ \ __al_linux_release_bitmap(NULL); \ } #define SAFISH_CALL(FUNC) SAFE_CALL(FUNC) #else #define SAFE_CALL(FUNC) FUNC #define SAFISH_CALL(FUNC) FUNC #endif /* bswap: * Toggles the endianess of a 32 bit integer. */ static unsigned long bswap(unsigned long n) { unsigned long a = n & 0xFF; unsigned long b = (n>>8) & 0xFF; unsigned long c = (n>>16) & 0xFF; unsigned long d = (n>>24) & 0xFF; return (a<<24) | (b<<16) | (c<<8) | d; } /* call_vbeaf_asm: * Calls a VBE/AF function using the version 1.0 style asm interface. */ static int call_vbeaf_asm(void *proc) { int ret; proc = (void *)((long)af_driver + (long)proc); #ifdef ALLEGRO_GCC /* use gcc-style inline asm */ asm ( " pushl %%ebx ; " " movl %%ecx, %%ebx ; " " call *%%edx ; " " popl %%ebx ; " : "=&a" (ret) /* return value in eax */ : "c" (af_driver), /* VBE/AF driver in ds:ebx */ "d" (proc) /* function ptr in edx */ : "memory" /* assume everything is clobbered */ ); #elif defined ALLEGRO_WATCOM /* use Watcom-style inline asm */ { int _af(void *func, AF_DRIVER *driver); #pragma aux _af = \ " call esi " \ \ parm [esi] [ebx] \ modify [ecx edx edi] \ value [eax]; ret = _af(proc, af_driver); } #else /* don't know what to do on this compiler */ ret = -1; #endif return ret; } /* vbeaf_no_wait: * Dummy wait-till-idle routine for non-accelerated drivers. */ static void vbeaf_no_wait(void) { } END_OF_STATIC_FUNCTION(vbeaf_no_wait); /* load_vbeaf_driver: * Tries to load the specified VBE/AF driver file, returning TRUE on * success. Allocates memory and reads the driver into it. */ static int load_vbeaf_driver(AL_CONST char *filename) { long size; PACKFILE *f; #ifdef ALLEGRO_LINUX /* on Linux. be paranoid and insist that vbeaf.drv belongs to root */ char tmp[128]; struct stat s; if (stat(uconvert_toascii(filename, tmp), &s) != 0) return 0; if ((s.st_uid != 0) || (s.st_mode & (S_IWGRP | S_IWOTH))) { uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("%s must only be writeable by root"), filename); return -1; } size = s.st_size; if (size <= 0) return 0; #else /* simple version for other platforms */ size = file_size(filename); if (size <= 0) return 0; #endif f = pack_fopen(filename, F_READ); if (!f) return 0; af_driver = _accel_driver = malloc(size); if (pack_fread(af_driver, size, f) != size) { free(af_driver); af_driver = _accel_driver = NULL; return 0; } pack_fclose(f); LOCK_DATA(af_driver, size); return 1; } /* initialise_freebeaf_extensions: * Prepares the FreeBE/AF extension functions. */ static void initialise_freebeaf_extensions(void) { typedef unsigned long (*EXT_INIT_FUNC)(AF_DRIVER *af, unsigned long id); EXT_INIT_FUNC ext_init; unsigned long magic; int v1, v2; #ifdef ALLEGRO_DOS void *ptr; #endif /* safety check */ if (!af_driver->OemExt) { faf_ext = 0; return; } /* call the extension init function */ ext_init = (EXT_INIT_FUNC)((long)af_driver + (long)af_driver->OemExt); magic = ext_init(af_driver, FAFEXT_INIT); /* check that it returned a nice magic number */ v1 = (magic>>8)&0xFF; v2 = magic&0xFF; if (((magic&0xFFFF0000) != FAFEXT_MAGIC) || (!uisdigit(v1)) || (!uisdigit(v2))) { faf_ext = 0; return; } faf_ext = (v1-'0')*10 + (v2-'0'); /* export libc and pmode functions if the driver wants them */ #ifdef ALLEGRO_DOS ptr = af_driver->OemExt(af_driver, FAFEXT_LIBC); if (ptr) _fill_vbeaf_libc_exports(ptr); ptr = af_driver->OemExt(af_driver, FAFEXT_PMODE); if (ptr) _fill_vbeaf_pmode_exports(ptr); #endif } /* initialise_vbeaf_driver: * Sets up the DPMI memory mappings required by the VBE/AF driver, * returning zero on success. */ static int initialise_vbeaf_driver(void) { int c; #ifdef ALLEGRO_DJGPP /* query driver for the FreeBE/AF farptr extension */ if (faf_ext > 0) faf_farptr = af_driver->OemExt(af_driver, FAFEXT_HWPTR); else faf_farptr = NULL; #else /* don't use farptr on any other platforms */ faf_farptr = NULL; #endif #ifdef ALLEGRO_DOS if (faf_farptr) { /* use farptr access */ for (c=0; c<4; c++) { faf_farptr->IOMemMaps[c].sel = 0; faf_farptr->IOMemMaps[c].offset = 0; } faf_farptr->BankedMem.sel = 0; faf_farptr->BankedMem.offset = 0; faf_farptr->LinearMem.sel = 0; faf_farptr->LinearMem.offset = 0; vbeaf_nearptr = FALSE; } else { /* enable nearptr access */ if (_crt0_startup_flags & _CRT0_FLAG_NEARPTR) { vbeaf_nearptr = FALSE; } else { if (__djgpp_nearptr_enable() == 0) return -2; vbeaf_nearptr = TRUE; } } #endif /* create mapping for MMIO ports */ for (c=0; c<4; c++) { if (af_driver->IOMemoryBase[c]) { if (_create_linear_mapping(af_memmap+c, af_driver->IOMemoryBase[c], af_driver->IOMemoryLen[c]) != 0) return -1; if (faf_farptr) { /* farptr IO mapping */ if (_create_selector(&faf_farptr->IOMemMaps[c].sel, af_memmap[c], af_driver->IOMemoryLen[c]) != 0) { _remove_linear_mapping(af_memmap+c); return -1; } faf_farptr->IOMemMaps[c].offset = 0; af_driver->IOMemMaps[c] = NULL; } else { /* nearptr IO mapping */ af_driver->IOMemMaps[c] = MVAL(af_memmap[c]); } } } /* create mapping for banked video RAM */ if (af_driver->BankedBasePtr) { if (_create_linear_mapping(&af_banked_mem, af_driver->BankedBasePtr, 0x10000) != 0) return -1; if (faf_farptr) { /* farptr banked vram mapping */ if (_create_selector(&faf_farptr->BankedMem.sel, af_banked_mem, 0x10000) != 0) { _remove_linear_mapping(&af_banked_mem); return -1; } faf_farptr->BankedMem.offset = 0; af_driver->BankedMem = NULL; } else { /* nearptr banked vram mapping */ af_driver->BankedMem = MVAL(af_banked_mem); } } /* create mapping for linear video RAM */ if (af_driver->LinearBasePtr) { if (_create_linear_mapping(&af_linear_mem, af_driver->LinearBasePtr, af_driver->LinearSize*1024) != 0) return -1; if (faf_farptr) { /* farptr linear vram mapping */ if (_create_selector(&faf_farptr->LinearMem.sel, af_linear_mem, af_driver->LinearSize*1024) != 0) { _remove_linear_mapping(&af_linear_mem); return -1; } faf_farptr->LinearMem.offset = 0; af_driver->LinearMem = NULL; } else { /* nearptr linear vram mapping */ af_driver->LinearMem = MVAL(af_linear_mem); } } /* callback functions: why are these needed? ugly, IMHO */ af_driver->Int86 = _af_int86; af_driver->CallRealMode = _af_call_rm; return 0; } /* find_vbeaf_mode: * Tries to find a VBE/AF mode number for the specified screen size. */ static int find_vbeaf_mode(int w, int h, int v_w, int v_h, int color_depth, AF_MODE_INFO *mode_info) { unsigned short *mode; /* search the list of modes */ for (mode = af_driver->AvailableModes; *mode != 0xFFFF; mode++) { /* retrieve the mode information block */ if (af_driver->GetVideoModeInfo(af_driver, *mode, mode_info) == 0) { /* check size and color depth */ if ((mode_info->XResolution == w) && (mode_info->YResolution == h) && (mode_info->BitsPerPixel == color_depth) && (mode_info->MaxScanLineWidth >= v_w)) { /* make sure the mode supports scrolling */ if ((v_w > w) || (v_h > h)) { if (!(mode_info->Attributes & 2)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Hardware scrolling not supported")); return 0; } } /* if it isn't FreeBE/AF, it must be UniVBE, so if we don't * have hardware acceleration we may as well just fail this * call and use VBE 3.0 instead. */ if ((!(mode_info->Attributes & 16)) && (!faf_id)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Hardware acceleration not available")); return 0; } return *mode; } } } ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Resolution not supported")); return 0; } /* set_vbeaf_mode: * Selects a VBE/AF graphics mode. */ static int set_vbeaf_mode(int mode, int w, int h, int v_w, int v_h, int *width, int *scrollable) { long wret = *width; int ret; if (gfx_vbeaf.linear) mode |= 0x4000; /* try to set a large virtual screen */ mode |= 0x1000; *scrollable = TRUE; saved_mode = mode; saved_vw = v_w; saved_vh = v_h; saved_wret = wret; ret = af_driver->SetVideoMode(af_driver, mode, v_w, v_h, &wret, 1, NULL); if ((ret != 0) && (v_w <= w) && (v_h <= h)) { /* if that didn't work, try to set a non-scrolling framebuffer */ mode &= ~0x1000; *scrollable = FALSE; saved_mode = mode; saved_wret = wret; ret = af_driver->SetVideoMode(af_driver, mode, v_w, v_h, &wret, 1, NULL); } *width = wret; return ret; } /* vbeaf_locate_driver: * locates and loads a VBE/AF driver. */ static int vbeaf_locate_driver(void) { static char *possible_filenames[] = { #ifdef ALLEGRO_DOS "c:\\vbeaf.drv", #else "/usr/local/lib/vbeaf.drv", "/usr/lib/vbeaf.drv", "/lib/vbeaf.drv", "/vbeaf.drv", #endif NULL }; char filename[1024], tmp1[1024], tmp2[128]; AL_CONST char *p; int ret, i, attrib; /* look for driver in the config file location */ p = get_config_string(uconvert_ascii("graphics", tmp1), uconvert_ascii("vbeaf_driver", tmp2), NULL); if ((p) && (ugetc(p))) { ustrzcpy(filename, sizeof(filename), p); if (ugetc(get_filename(filename)) == 0) { append_filename(filename, filename, uconvert_ascii("vbeaf.drv", tmp1), sizeof(filename)); } else { if (file_exists(filename, FA_DIREC, &attrib)) { if (attrib & FA_DIREC) append_filename(filename, filename, uconvert_ascii("vbeaf.drv", tmp1), sizeof(filename)); } } ret = load_vbeaf_driver(filename); if (ret) goto found_it; } /* look for driver in the same directory as the program */ get_executable_name(tmp1, sizeof(tmp1)); replace_filename(filename, tmp1, uconvert_ascii("vbeaf.drv", tmp2), sizeof(filename)); ret = load_vbeaf_driver(filename); if (ret) goto found_it; /* look for driver in the default location */ for (i=0; possible_filenames[i]; i++) { ret = load_vbeaf_driver(uconvert_ascii(possible_filenames[i], tmp1)); if (ret) goto found_it; } /* check the environment for a location */ p = getenv("VBEAF_PATH"); if (p) { append_filename(filename, uconvert_ascii(p, tmp1), uconvert_ascii("vbeaf.drv", tmp2), sizeof(filename)); ret = load_vbeaf_driver(filename); if (ret) goto found_it; } /* oops, no driver */ ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can't find VBEAF.DRV")); ret = FALSE; /* got it! */ found_it: return ret; } /* vbeaf_lowlevel_init: * loads the VBE/AF driver and initializes it. */ static int vbeaf_lowlevel_init(void) { int ret; /* check the driver ID string */ if (strcmp(af_driver->Signature, "VBEAF.DRV") != 0) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Bad VBE/AF driver ID string")); return FALSE; } /* check the VBE/AF version number */ if (af_driver->Version < 0x200) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Obsolete VBE/AF version (need 2.0 or greater)")); return FALSE; } /* to run on Linux, we need to be God */ #ifdef ALLEGRO_LINUX if (!__al_linux_have_ioperms) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("This driver needs root privileges")); return FALSE; } _vbeaf_selector = _default_ds(); #endif /* detect and initialise the FreeBE/AF extensions */ if (strstr(af_driver->OemVendorName, "FreeBE")) { faf_id = TRUE; initialise_freebeaf_extensions(); } else { faf_id = FALSE; faf_ext = 0; } /* special setup for Plug and Play hardware */ if (call_vbeaf_asm(af_driver->PlugAndPlayInit) != 0) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF Plug and Play initialisation failed")); return FALSE; } /* deal with all that DPMI memory mapping crap */ ret = initialise_vbeaf_driver(); if (ret != 0) { vbeaf_exit(NULL); if (ret == -2) ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF nearptrs not supported on this platform")); else ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can't map memory for VBE/AF")); return FALSE; } /* low level driver initialisation */ if (call_vbeaf_asm(af_driver->InitDriver) != 0) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF device not present")); return FALSE; } return TRUE; } /* vbeaf_init: * Tries to enter the specified graphics mode, and makes a screen bitmap * for it. */ static BITMAP *vbeaf_init(int w, int h, int v_w, int v_h, int color_depth) { BITMAP *b; AF_MODE_INFO mode_info; int bpp = BYTES_PER_PIXEL(color_depth); int bytes_per_scanline, width, height; int scrollable, mode; int vseg; int rs, gs, bs; char tmp1[512]; void *vaddr; /* Do not continue if this version of Allegro was built in C-only mode. * The bank switchers assume asm-mode calling conventions, but the * library would try to call them with C calling conventions. */ #ifdef ALLEGRO_USE_C return NULL; #endif /* locate and load VBE/AF driver from disk */ if (!vbeaf_locate_driver()) return NULL; LOCK_VARIABLE(af_driver); LOCK_VARIABLE(_accel_driver); LOCK_VARIABLE(_accel_active); LOCK_VARIABLE(_accel_set_bank); LOCK_VARIABLE(_accel_idle); LOCK_VARIABLE(vbeaf_cur_on); LOCK_VARIABLE(vbeaf_cur_x); LOCK_VARIABLE(vbeaf_cur_y); LOCK_FUNCTION(_accel_bank_switch); LOCK_FUNCTION(_accel_bank_stub); LOCK_FUNCTION(_af_wrapper); LOCK_FUNCTION(vbeaf_no_wait); LOCK_FUNCTION(vbeaf_move_mouse); LOCK_FUNCTION(vbeaf_draw_sprite); LOCK_FUNCTION(vbeaf_blit_from_memory); /* init the currently loaded VBE/AF driver */ if (!vbeaf_lowlevel_init()) return NULL; /* bodge to work around bugs in the present (6.51) version of UniVBE */ if ((v_w > w) && (!faf_id)) { vbeaf_exit(NULL); ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("SciTech VBE/AF drivers do not support wide virtual screens")); return NULL; } /* get ourselves a mode number */ mode = find_vbeaf_mode(w, h, v_w, v_h, color_depth, &mode_info); if (mode == 0) { vbeaf_exit(NULL); return NULL; } gfx_vbeaf.vid_mem = af_driver->TotalMemory * 1024; vaddr = NULL; if (mode_info.Attributes & 8) { /* linear framebuffer */ gfx_vbeaf.linear = TRUE; gfx_vbeaf.bank_size = gfx_vbeaf.bank_gran = 0; gfx_vbeaf.vid_phys_base = af_driver->LinearBasePtr; bytes_per_scanline = mode_info.LinBytesPerScanLine; if (faf_farptr) { vaddr = (void *)faf_farptr->LinearMem.offset; vseg = faf_farptr->LinearMem.sel; } else { vaddr = af_driver->LinearMem; vseg = _default_ds(); } } else { /* banked framebuffer */ gfx_vbeaf.linear = FALSE; gfx_vbeaf.bank_size = 65536; gfx_vbeaf.bank_gran = af_driver->BankSize * 1024; gfx_vbeaf.vid_phys_base = af_driver->BankedBasePtr; bytes_per_scanline = mode_info.BytesPerScanLine; if (faf_farptr) { vaddr = (void *)faf_farptr->BankedMem.offset; vseg = faf_farptr->BankedMem.sel; } else { vaddr = af_driver->BankedMem; vseg = _default_ds(); } } width = MAX(bytes_per_scanline, v_w*bpp); height = MAX(h, v_h); _sort_out_virtual_width(&width, &gfx_vbeaf); if (width * height > gfx_vbeaf.vid_mem) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Insufficient video memory")); vbeaf_exit(NULL); return NULL; } /* set the mode */ if (set_vbeaf_mode(mode, w, h, width/bpp, height, &width, &scrollable) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Failed to set VBE/AF mode")); vbeaf_exit(NULL); return NULL; } in_af_mode = TRUE; _accel_active = FALSE; if (scrollable) height = MAX(height, (int)af_driver->OffscreenEndY+1); if ((width/bpp < v_w) || (width/bpp < w) || (height < v_h) || (height < h)) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Virtual screen size too large")); vbeaf_exit(NULL); return NULL; } /* construct the screen bitmap */ b = _make_bitmap(width/bpp, height, (unsigned long)vaddr, &gfx_vbeaf, color_depth, width); if (!b) { vbeaf_exit(NULL); return NULL; } b->seg = vseg; /* set up the /AF driver state */ af_driver->SetActiveBuffer(af_driver, 0); af_driver->SetVisibleBuffer(af_driver, 0, 0); if (af_driver->EnableDirectAccess) af_driver->EnableDirectAccess(af_driver); if (af_driver->SetClipRect) af_driver->SetClipRect(af_driver, 0, 0, b->w-1, b->h-1); _accel_set_bank = af_driver->SetBank; if (af_driver->EnableDirectAccess) _accel_idle = af_driver->EnableDirectAccess; else if (af_driver->WaitTillIdle) _accel_idle = af_driver->WaitTillIdle; else _accel_idle = vbeaf_no_wait; if (gfx_vbeaf.linear) { if (_accel_idle == vbeaf_no_wait) b->write_bank = b->read_bank = _stub_bank_switch; else b->write_bank = b->read_bank = _accel_bank_stub; } else { b->write_bank = b->read_bank = _accel_bank_switch; b->id |= BMP_ID_NOBLIT; } vbeaf_xscroll = vbeaf_yscroll = 0; gfx_vbeaf.w = b->cr = w; gfx_vbeaf.h = b->cb = h; /* set up the truecolor pixel format */ #if (defined ALLEGRO_COLOR16) || (defined ALLEGRO_COLOR24) || (defined ALLEGRO_COLOR32) if (gfx_vbeaf.linear) { rs = mode_info.LinRedFieldPosition; gs = mode_info.LinGreenFieldPosition; bs = mode_info.LinBlueFieldPosition; } else { rs = mode_info.RedFieldPosition; gs = mode_info.GreenFieldPosition; bs = mode_info.BlueFieldPosition; } switch (color_depth) { #ifdef ALLEGRO_COLOR16 case 15: _rgb_r_shift_15 = rs; _rgb_g_shift_15 = gs; _rgb_b_shift_15 = bs; break; case 16: _rgb_r_shift_16 = rs; _rgb_g_shift_16 = gs; _rgb_b_shift_16 = bs; break; #endif #ifdef ALLEGRO_COLOR24 case 24: _rgb_r_shift_24 = rs; _rgb_g_shift_24 = gs; _rgb_b_shift_24 = bs; break; #endif #ifdef ALLEGRO_COLOR32 case 32: _rgb_r_shift_32 = rs; _rgb_g_shift_32 = gs; _rgb_b_shift_32 = bs; break; #endif } #endif orig_vline = _screen_vtable.vline; orig_hline = _screen_vtable.hline; orig_line = _screen_vtable.line; orig_rectfill = _screen_vtable.rectfill; orig_draw_glyph = _screen_vtable.draw_glyph; orig_draw_sprite = _screen_vtable.draw_sprite; orig_masked_blit = _screen_vtable.masked_blit; /* is triple buffering supported? */ if (mode_info.Attributes & 2048) { gfx_vbeaf.request_scroll = vbeaf_request_scroll; gfx_vbeaf.poll_scroll = vbeaf_poll_scroll; } else { gfx_vbeaf.request_scroll = NULL; gfx_vbeaf.poll_scroll = NULL; } /* are hardware cursors supported? */ if ((mode_info.Attributes & 64) && (af_driver->SetCursor)) { gfx_vbeaf.set_mouse_sprite = vbeaf_set_mouse_sprite; gfx_vbeaf.show_mouse = vbeaf_show_mouse; gfx_vbeaf.hide_mouse = vbeaf_hide_mouse; gfx_vbeaf.move_mouse = vbeaf_move_mouse; } else { gfx_vbeaf.set_mouse_sprite = NULL; gfx_vbeaf.show_mouse = NULL; gfx_vbeaf.hide_mouse = NULL; gfx_vbeaf.move_mouse = NULL; } /* accelerated scanline fills? */ if (af_driver->DrawScan) gfx_capabilities |= (GFX_HW_HLINE | GFX_HW_HLINE_XOR); if (af_driver->DrawPattScan) gfx_capabilities |= GFX_HW_HLINE_SOLID_PATTERN; if (af_driver->DrawColorPattScan) gfx_capabilities |= GFX_HW_HLINE_COPY_PATTERN; /* accelerated line drawing? */ if (af_driver->DrawLine) gfx_capabilities |= (GFX_HW_LINE | GFX_HW_LINE_XOR); /* accelerated rectangle fills? */ if (af_driver->DrawRect) { _screen_vtable.clear_to_color = vbeaf_clear_to_color; gfx_capabilities |= (GFX_HW_FILL | GFX_HW_FILL_XOR); } if (af_driver->DrawPattRect) gfx_capabilities |= GFX_HW_FILL_SOLID_PATTERN; if (af_driver->DrawColorPattRect) gfx_capabilities |= GFX_HW_FILL_COPY_PATTERN; /* accelerated triangle drawing? */ if (af_driver->DrawTrap) gfx_capabilities |= (GFX_HW_TRIANGLE | GFX_HW_TRIANGLE_XOR); /* accelerated monochrome text output? */ if (af_driver->PutMonoImage) { _screen_vtable.draw_glyph = vbeaf_draw_glyph; gfx_capabilities |= GFX_HW_GLYPH; } /* accelerated video memory blits? */ if (af_driver->BitBlt) { _screen_vtable.blit_to_self = vbeaf_blit_to_self; _screen_vtable.blit_to_self_forward = vbeaf_blit_to_self; _screen_vtable.blit_to_self_backward = vbeaf_blit_to_self; gfx_capabilities |= GFX_HW_VRAM_BLIT; } /* accelerated blits from system memory? */ if (af_driver->BitBltSys) { _screen_vtable.blit_from_memory = vbeaf_blit_from_memory; _screen_vtable.blit_from_system = vbeaf_blit_from_memory; gfx_capabilities |= GFX_HW_MEM_BLIT; } /* accelerated masked blits? */ if ((af_driver->SrcTransBlt) || (af_driver->SrcTransBltSys)) { _screen_vtable.masked_blit = vbeaf_masked_blit; _screen_vtable.draw_sprite = vbeaf_draw_sprite; if (_screen_vtable.draw_256_sprite == orig_draw_sprite) _screen_vtable.draw_256_sprite = vbeaf_draw_sprite; if (af_driver->SrcTransBlt) gfx_capabilities |= GFX_HW_VRAM_BLIT_MASKED; if (af_driver->SrcTransBltSys) gfx_capabilities |= GFX_HW_MEM_BLIT_MASKED; } /* set up the VBE/AF description string */ ustrzcpy(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(af_driver->OemVendorName, tmp1)); if (gfx_vbeaf.linear) ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", linear", tmp1)); else ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", banked", tmp1)); if (faf_ext > 0) uszprintf(vbeaf_desc+ustrsize(vbeaf_desc), sizeof(vbeaf_desc) - ustrsize(vbeaf_desc), uconvert_ascii(", FreeBE ex%02d", tmp1), faf_ext); else if (faf_id) ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", FreeBE noex", tmp1)); if (faf_farptr) ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", farptr", tmp1)); /* is this an accelerated or dumb framebuffer mode? */ if (mode_info.Attributes & 16) { gfx_vbeaf.drawing_mode = vbeaf_drawing_mode; vbeaf_drawing_mode(); ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", accel", tmp1)); } else { gfx_vbeaf.drawing_mode = NULL; ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", noaccel", tmp1)); } gfx_vbeaf.desc = vbeaf_desc; #ifdef ALLEGRO_LINUX __al_linux_console_graphics(); b->vtable->acquire = __al_linux_acquire_bitmap; b->vtable->release = __al_linux_release_bitmap; #endif return b; } /* vbeaf_exit: * Shuts down the VBE/AF driver. */ static void vbeaf_exit(BITMAP *b) { int c; /* shut down the driver */ if (in_af_mode) { if (af_driver->EnableDirectAccess) af_driver->EnableDirectAccess(af_driver); else if (af_driver->WaitTillIdle) af_driver->WaitTillIdle(af_driver); af_driver->RestoreTextMode(af_driver); in_af_mode = FALSE; } /* undo memory mappings */ if (faf_farptr) { for (c=0; c<4; c++) _remove_selector(&faf_farptr->IOMemMaps[c].sel); _remove_selector(&faf_farptr->BankedMem.sel); _remove_selector(&faf_farptr->LinearMem.sel); } for (c=0; c<4; c++) _remove_linear_mapping(af_memmap+c); _remove_linear_mapping(&af_banked_mem); _remove_linear_mapping(&af_linear_mem); if (af_driver) { free(af_driver); af_driver = _accel_driver = NULL; } #ifdef ALLEGRO_DOS if (vbeaf_nearptr) { __djgpp_nearptr_disable(); vbeaf_nearptr = FALSE; } #endif #ifdef ALLEGRO_LINUX __al_linux_console_text(); #endif } /* vbeaf_save: * Saves the graphics state. */ static void vbeaf_save(void) { if (af_driver->EnableDirectAccess) af_driver->EnableDirectAccess(af_driver); else if (af_driver->WaitTillIdle) af_driver->WaitTillIdle(af_driver); af_driver->RestoreTextMode(af_driver); in_af_mode = FALSE; } /* vbeaf_restore: * Restores the graphics state. */ static void vbeaf_restore(void) { long wret = saved_wret; af_driver->SetVideoMode(af_driver, saved_mode, saved_vw, saved_vh, &wret, 1, NULL); af_driver->SetActiveBuffer(af_driver, 0); af_driver->SetVisibleBuffer(af_driver, 0, 0); if (af_driver->EnableDirectAccess) af_driver->EnableDirectAccess(af_driver); if (af_driver->SetClipRect) af_driver->SetClipRect(af_driver, 0, 0, SCREEN_W-1, SCREEN_H-1); if (gfx_vbeaf.drawing_mode) gfx_vbeaf.drawing_mode(); vbeaf_scroll(vbeaf_xscroll, vbeaf_yscroll); in_af_mode = TRUE; } /* vbeaf_fetch_mode_list: * Attempts to create a list of valid video modes for the VBE/AF driver. * Returns the mode list on success or NULL on failure. */ static GFX_MODE_LIST *vbeaf_fetch_mode_list(void) { GFX_MODE_LIST *gfx_mode_list; AF_MODE_INFO *mode_info; unsigned short *mode; int vbeaf_was_off; mode_info = malloc(sizeof(AF_MODE_INFO)); if (!mode_info) return NULL; /* make sure VBE/AF interface is enabled! */ if (!af_driver) { if (!vbeaf_locate_driver()) { if (mode_info) free(mode_info); return NULL; } if (!vbeaf_lowlevel_init()) { if (mode_info) free(mode_info); return NULL; } vbeaf_was_off = TRUE; } else vbeaf_was_off = FALSE; /* start building mode-list */ gfx_mode_list = malloc(sizeof(GFX_MODE_LIST)); if (!gfx_mode_list) { if (mode_info) free(mode_info); return NULL; } gfx_mode_list->mode = NULL; gfx_mode_list->num_modes = 0; /* create mode list */ for (mode = af_driver->AvailableModes; *mode != 0xFFFF; mode++) { gfx_mode_list->mode = _al_sane_realloc(gfx_mode_list->mode, sizeof(GFX_MODE) * (gfx_mode_list->num_modes + 1)); if (!gfx_mode_list->mode) { if (mode_info) free(mode_info); if (gfx_mode_list) free(gfx_mode_list); return NULL; } if (af_driver->GetVideoModeInfo(af_driver, *mode, mode_info) != 0) { if (mode_info) free(mode_info); if (gfx_mode_list->mode) free(gfx_mode_list->mode); if (gfx_mode_list) free(gfx_mode_list); return NULL; } gfx_mode_list->mode[gfx_mode_list->num_modes].width = mode_info->XResolution; gfx_mode_list->mode[gfx_mode_list->num_modes].height = mode_info->YResolution; gfx_mode_list->mode[gfx_mode_list->num_modes].bpp = mode_info->BitsPerPixel; gfx_mode_list->num_modes++; } /* terminate mode list */ gfx_mode_list->mode = _al_sane_realloc(gfx_mode_list->mode, sizeof(GFX_MODE) * (gfx_mode_list->num_modes + 1)); if (!gfx_mode_list->mode) { if (mode_info) free(mode_info); if (gfx_mode_list) free(gfx_mode_list); return NULL; } gfx_mode_list->mode[gfx_mode_list->num_modes].width = 0; gfx_mode_list->mode[gfx_mode_list->num_modes].height = 0; gfx_mode_list->mode[gfx_mode_list->num_modes].bpp = 0; /* shut down VBE/AF interface if it wasn't previously loaded */ if (vbeaf_was_off) vbeaf_exit(NULL); if (mode_info) free(mode_info); return gfx_mode_list; } /* vbeaf_vsync: * VBE/AF vsync routine, needed for cards that don't emulate the VGA * blanking registers. VBE/AF doesn't provide a vsync function, but we * can emulate it by altering the display start address with the vsync * flag set. */ static void vbeaf_vsync(void) { vbeaf_scroll(vbeaf_xscroll, vbeaf_yscroll); } /* vbeaf_scroll: * Hardware scrolling routine. */ static int vbeaf_scroll(int x, int y) { int moved = (vbeaf_xscroll != x) || (vbeaf_yscroll != y); vbeaf_xscroll = x; vbeaf_yscroll = y; SAFISH_CALL( if (_wait_for_vsync && af_driver->WaitTillIdle) af_driver->WaitTillIdle(af_driver); af_driver->SetDisplayStart(af_driver, x, y, 1); ); if ((vbeaf_cur_bmp) && (moved)) vbeaf_move_mouse(vbeaf_cur_x, vbeaf_cur_y); return 0; } /* vbeaf_set_palette_range: * Uses VBE/AF functions to set the palette. */ static void vbeaf_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync) { AF_PALETTE tmp[256]; int c; for (c=from; c<=to; c++) { tmp[c-from].red = p[c].r << 2; tmp[c-from].green = p[c].g << 2; tmp[c-from].blue = p[c].b << 2; tmp[c-from].alpha = 0; } SAFISH_CALL( af_driver->SetPaletteData(af_driver, tmp, to-from+1, from, (vsync ? 1 : 0)); ); } /* vbeaf_request_scroll: * Triple buffering initiate routine. */ static int vbeaf_request_scroll(int x, int y) { vbeaf_xscroll = x; vbeaf_yscroll = y; SAFISH_CALL( if (af_driver->WaitTillIdle) af_driver->WaitTillIdle(af_driver); af_driver->SetDisplayStart(af_driver, x, y, 0); ); if (vbeaf_cur_bmp) vbeaf_move_mouse(vbeaf_cur_x, vbeaf_cur_y); return 0; } /* vbeaf_poll_scroll: * Triple buffering test routine. */ static int vbeaf_poll_scroll(void) { int ret; SAFISH_CALL( ret = af_driver->GetDisplayStartStatus(af_driver); ); return (ret) ? FALSE : TRUE; } /* vbeaf_set_mouse_sprite: * Attempts to download a new hardware cursor graphic, returning zero on * success or non-zero if this image is unsuitable. */ static int vbeaf_set_mouse_sprite(BITMAP *sprite, int xfocus, int yfocus) { AF_CURSOR cursor; int bpp = bitmap_color_depth(sprite); int c, x, y; int iszero; /* hardware cursors cannot be larger than 32x32 */ if ((sprite->w > 32) || (sprite->h > 32)) return -1; /* clear the cursor data */ for (c=0; c<32; c++) { cursor.andMask[c] = 0; cursor.xorMask[c] = 0; } vbeaf_cur_c1 = -1; vbeaf_cur_c2 = -1; /* scan through the pointer image */ for (y=0; yh; y++) { for (x=0; xw; x++) { c = getpixel(sprite, x, y); if (c == bitmap_mask_color(sprite)) { /* skip masked pixels */ } else if (c == vbeaf_cur_c1) { /* color #1 pixel */ cursor.andMask[y] |= 0x80000000>>x; cursor.xorMask[y] |= 0x80000000>>x; } else if (c == vbeaf_cur_c2) { /* color #2 pixel */ cursor.andMask[y] |= 0x80000000>>x; } else { /* check whether this pixel value is zero */ if (bpp == 8) { iszero = ((getr_depth(bpp, c) == getr_depth(bpp, 0)) && (getg_depth(bpp, c) == getg_depth(bpp, 0)) && (getb_depth(bpp, c) == getb_depth(bpp, 0))); } else { iszero = ((getr_depth(bpp, c) == 0) && (getg_depth(bpp, c) == 0) && (getb_depth(bpp, c) == 0)); } if ((vbeaf_cur_c2 < 0) && (iszero)) { /* zero pixel value = color #2 */ vbeaf_cur_c2 = c; cursor.andMask[y] |= 0x80000000>>x; } else if (vbeaf_cur_c1 < 0) { /* other pixel value = color #1 */ vbeaf_cur_c1 = c; cursor.andMask[y] |= 0x80000000>>x; cursor.xorMask[y] |= 0x80000000>>x; } else { /* it's not cool if there are more than two colors! */ return -1; } } } } /* flip the endianess */ for (c=0; c<32; c++) { cursor.andMask[c] = bswap(cursor.andMask[c]); cursor.xorMask[c] = bswap(cursor.xorMask[c]); } cursor.hotx = xfocus; cursor.hoty = yfocus; /* download to the hardware */ SAFISH_CALL( af_driver->SetCursor(af_driver, &cursor); if ((bpp > 8) && (vbeaf_cur_c1 >= 0)) { af_driver->SetCursorColor(af_driver, getr_depth(bpp, vbeaf_cur_c1), getg_depth(bpp, vbeaf_cur_c1), getb_depth(bpp, vbeaf_cur_c1)); } ); return 0; } /* vbeaf_show_mouse: * Turns on the hardware cursor, returning zero on success. */ static int vbeaf_show_mouse(BITMAP *bmp, int x, int y) { if (bitmap_color_depth(bmp) == 8) { if (vbeaf_cur_c2 >= 0) { /* check that the palette contains a valid zero color */ if ((getr_depth(8, vbeaf_cur_c2) != getr_depth(8, 0)) || (getg_depth(8, vbeaf_cur_c2) != getg_depth(8, 0)) || (getb_depth(8, vbeaf_cur_c2) != getb_depth(8, 0))) return -1; } /* set the cursor color */ if (vbeaf_cur_c1 >= 0) { SAFISH_CALL( af_driver->SetCursorColor(af_driver, vbeaf_cur_c1, 0, 0); ); } } vbeaf_cur_bmp = bmp; vbeaf_cur_on = FALSE; vbeaf_move_mouse(x, y); return 0; } /* vbeaf_hide_mouse: * Gets rid of the hardware cursor. */ static void vbeaf_hide_mouse(void) { SAFISH_CALL( af_driver->ShowCursor(af_driver, 0); ); vbeaf_cur_bmp = NULL; vbeaf_cur_on = FALSE; } /* vbeaf_move_mouse: * Sets the hardware cursor position. */ static void vbeaf_move_mouse(int x, int y) { int hx, hy; int onscreen; hx = x + vbeaf_cur_bmp->x_ofs - vbeaf_xscroll; hy = y + vbeaf_cur_bmp->y_ofs - vbeaf_yscroll; onscreen = (hx >= 0) && (hx < SCREEN_W) && (hy >= 0) && (hy < SCREEN_H); SAFISH_CALL( if (onscreen) { af_driver->SetCursorPos(af_driver, hx, hy); if (!vbeaf_cur_on) { af_driver->ShowCursor(af_driver, 1); vbeaf_cur_on = TRUE; } } else { if (vbeaf_cur_on) { af_driver->ShowCursor(af_driver, 0); vbeaf_cur_on = FALSE; } } ); vbeaf_cur_x = x; vbeaf_cur_y = y; } END_OF_STATIC_FUNCTION(vbeaf_move_mouse); /* vbeaf_drawing_mode: * Hook to tell us that the drawing mode has been changed, so we may need * to alter some of our vtable entries. */ static void vbeaf_drawing_mode(void) { vbeaf_pattern = NULL; if ((_drawing_mode == DRAW_MODE_SOLID) || (_drawing_mode == DRAW_MODE_XOR)) { /* easy, everything supports solid and XOR drawing */ _screen_vtable.hline = (af_driver->DrawScan) ? vbeaf_hline : orig_hline; _screen_vtable.vline = (af_driver->DrawLine) ? vbeaf_vline_a : ((af_driver->DrawRect) ? vbeaf_vline_b : orig_vline); _screen_vtable.line = (af_driver->DrawLine) ? vbeaf_line : orig_line; _screen_vtable.rectfill = (af_driver->DrawRect) ? vbeaf_rectfill : orig_rectfill; _screen_vtable.triangle = (af_driver->DrawTrap) ? vbeaf_triangle : NULL; vbeaf_fg_mix = vbeaf_bg_mix = (_drawing_mode == DRAW_MODE_XOR) ? 3 : 0; SAFISH_CALL( af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); return; } if ((_drawing_mode == DRAW_MODE_COPY_PATTERN) && (_drawing_pattern->w <= 8) && (_drawing_pattern->h <= 8)) { /* color patterns can be done in hardware if they are small enough */ _screen_vtable.hline = (af_driver->DrawColorPattScan) ? vbeaf_hline : orig_hline; _screen_vtable.vline = (af_driver->DrawColorPattRect) ? vbeaf_vline_b : orig_vline; _screen_vtable.line = orig_line; _screen_vtable.rectfill = (af_driver->DrawColorPattRect) ? vbeaf_rectfill : orig_rectfill; _screen_vtable.triangle = NULL; vbeaf_fg_mix = vbeaf_bg_mix = 0; SAFISH_CALL( af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); return; } if (((_drawing_mode == DRAW_MODE_SOLID_PATTERN) || (_drawing_mode == DRAW_MODE_MASKED_PATTERN)) && (_drawing_pattern->w <= 8) && (_drawing_pattern->h <= 8)) { /* mono patterns can be done in hardware if they are small enough */ _screen_vtable.hline = (af_driver->DrawPattScan) ? vbeaf_hline : orig_hline; _screen_vtable.vline = (af_driver->DrawPattRect) ? vbeaf_vline_b : orig_vline; _screen_vtable.line = orig_line; _screen_vtable.rectfill = (af_driver->DrawPattRect) ? vbeaf_rectfill : orig_rectfill; _screen_vtable.triangle = NULL; vbeaf_fg_mix = 0; vbeaf_bg_mix = (_drawing_mode == DRAW_MODE_MASKED_PATTERN) ? 4 : 0; SAFISH_CALL( af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); return; } /* urgh, have to use software drawing functions for this mode */ _screen_vtable.vline = orig_vline; _screen_vtable.hline = orig_hline; _screen_vtable.line = orig_line; _screen_vtable.rectfill = orig_rectfill; _screen_vtable.triangle = NULL; vbeaf_fg_mix = vbeaf_bg_mix = 0; SAFISH_CALL( af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); } /* prepare_color_pattern: * Sets up the hardware ready for a colored pattern drawing operation. */ static void prepare_color_pattern(BITMAP *bmp) { static unsigned long pattern[64]; int x, y, xx, yy, xo, yo; if (vbeaf_pattern != bmp) { xo = _drawing_x_anchor + bmp->x_ofs; yo = _drawing_y_anchor + bmp->y_ofs; switch (bitmap_color_depth(bmp)) { #ifdef ALLEGRO_COLOR8 case 8: for (y=0; y<8; y++) { for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; pattern[y*8+x] = _drawing_pattern->line[yy][xx]; } } break; #endif #ifdef ALLEGRO_COLOR16 case 15: case 16: for (y=0; y<8; y++) { for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; pattern[y*8+x] = ((unsigned short *)_drawing_pattern->line[yy])[xx]; } } break; #endif #ifdef ALLEGRO_COLOR24 case 24: for (y=0; y<8; y++) { for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; pattern[y*8+x] = *((unsigned long *)(_drawing_pattern->line[yy]+xx*3)) & 0xFFFFFF; } } break; #endif #ifdef ALLEGRO_COLOR32 case 32: for (y=0; y<8; y++) { for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; pattern[y*8+x] = ((unsigned long *)_drawing_pattern->line[yy])[xx]; } } break; #endif } af_driver->Set8x8ColorPattern(af_driver, 0, pattern); af_driver->Use8x8ColorPattern(af_driver, 0); vbeaf_pattern = bmp; } } /* prepare_mono_pattern: * Sets up the hardware ready for a mono pattern drawing operation. */ static void prepare_mono_pattern(BITMAP *bmp) { static unsigned char pattern[8]; int x, y, xx, yy, xo, yo; if (vbeaf_pattern != bmp) { xo = _drawing_x_anchor + bmp->x_ofs; yo = _drawing_y_anchor + bmp->y_ofs; switch (bitmap_color_depth(bmp)) { #ifdef ALLEGRO_COLOR16 case 8: for (y=0; y<8; y++) { pattern[y] = 0; for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; if (_drawing_pattern->line[yy][xx]) pattern[y] |= (0x80>>x); } } break; #endif #ifdef ALLEGRO_COLOR16 case 15: case 16: for (y=0; y<8; y++) { pattern[y] = 0; for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; if (((unsigned short *)_drawing_pattern->line[yy])[xx] != bitmap_mask_color(bmp)) pattern[y] |= (0x80>>x); } } break; #endif #ifdef ALLEGRO_COLOR24 case 24: for (y=0; y<8; y++) { pattern[y] = 0; for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; if ((*((unsigned long *)(_drawing_pattern->line[yy]+xx*3)) & 0xFFFFFF) != MASK_COLOR_24) pattern[y] |= (0x80>>x); } } break; #endif #ifdef ALLEGRO_COLOR32 case 32: for (y=0; y<8; y++) { pattern[y] = 0; for (x=0; x<8; x++) { xx = (x-xo) & _drawing_x_mask; yy = (y-yo) & _drawing_y_mask; if (((unsigned long *)_drawing_pattern->line[yy])[xx] != MASK_COLOR_32) pattern[y] |= (0x80>>x); } } break; #endif } af_driver->Set8x8MonoPattern(af_driver, pattern); vbeaf_pattern = bmp; } } /* go_accel: * Prepares the hardware for an accelerated drawing operation. */ static INLINE void go_accel(void) { /* turn on the accelerator */ if (!_accel_active) { if (af_driver->DisableDirectAccess) af_driver->DisableDirectAccess(af_driver); _accel_active = TRUE; } } /* vbeaf_hline: * Accelerated scanline filling routine. */ static void vbeaf_hline(BITMAP *bmp, int x1, int y, int x2, int color) { if (x1 > x2) { int tmp = x1; x1 = x2; x2 = tmp; } if (bmp->clip) { if ((y < bmp->ct) || (y >= bmp->cb)) return; if (x1 < bmp->cl) x1 = bmp->cl; if (x2 >= bmp->cr) x2 = bmp->cr-1; if (x2 < x1) return; } SAFISH_CALL( go_accel(); switch (_drawing_mode) { case DRAW_MODE_SOLID: case DRAW_MODE_XOR: /* normal scanline fill */ af_driver->DrawScan(af_driver, color, y+bmp->y_ofs, x1+bmp->x_ofs, x2+bmp->x_ofs+1); break; case DRAW_MODE_COPY_PATTERN: /* colored pattern scanline fill */ prepare_color_pattern(bmp); af_driver->DrawColorPattScan(af_driver, y+bmp->y_ofs, x1+bmp->x_ofs, x2+bmp->x_ofs+1); break; case DRAW_MODE_SOLID_PATTERN: case DRAW_MODE_MASKED_PATTERN: /* mono pattern scanline fill */ prepare_mono_pattern(bmp); af_driver->DrawPattScan(af_driver, color, 0, y+bmp->y_ofs, x1+bmp->x_ofs, x2+bmp->x_ofs+1); break; } ); } /* vbeaf_vline_a: * Accelerated vertical line drawer, using the VBE/AF line primitive. */ static void vbeaf_vline_a(BITMAP *bmp, int x, int y1, int y2, int color) { if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if (bmp->clip) { if ((x < bmp->cl) || (x >= bmp->cr)) return; if (y1 < bmp->ct) y1 = bmp->ct; if (y2 >= bmp->cb) y2 = bmp->cb-1; if (y2 < y1) return; } SAFISH_CALL( go_accel(); af_driver->DrawLine(af_driver, color, itofix(x+bmp->x_ofs), itofix(y1+bmp->y_ofs), itofix(x+bmp->x_ofs), itofix(y2+bmp->y_ofs)); ); } /* vbeaf_vline_b: * Accelerated vertical line drawer, using the VBE/AF rectangle primitive. */ static void vbeaf_vline_b(BITMAP *bmp, int x, int y1, int y2, int color) { if (y1 > y2) { int tmp = y1; y1 = y2; y2 = tmp; } if (bmp->clip) { if ((x < bmp->cl) || (x >= bmp->cr)) return; if (y1 < bmp->ct) y1 = bmp->ct; if (y2 >= bmp->cb) y2 = bmp->cb-1; if (y2 < y1) return; } SAFISH_CALL( go_accel(); switch (_drawing_mode) { case DRAW_MODE_SOLID: case DRAW_MODE_XOR: /* mono vertical line */ af_driver->DrawRect(af_driver, color, x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1); break; case DRAW_MODE_COPY_PATTERN: /* colored pattern vertical line */ prepare_color_pattern(bmp); af_driver->DrawColorPattRect(af_driver, x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1); break; case DRAW_MODE_SOLID_PATTERN: case DRAW_MODE_MASKED_PATTERN: /* mono pattern vertical line */ prepare_mono_pattern(bmp); af_driver->DrawPattRect(af_driver, color, 0, x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1); break; } ); } /* vbeaf_line: * Accelerated line drawer. */ static void vbeaf_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) { int sx, sy, dx, dy, t; if (bmp->clip) { sx = x1; sy = y1; dx = x2; dy = y2; if (sx > dx) { t = sx; sx = dx; dx = t; } if (sy > dy) { t = sy; sy = dy; dy = t; } if ((sx >= bmp->cr) || (sy >= bmp->cb) || (dx < bmp->cl) || (dy < bmp->ct)) return; if ((sx < bmp->cl) || (sy < bmp->ct) || (dx >= bmp->cr) || (dy >= bmp->cb)) { orig_line(bmp, x1, y1, x2, y2, color); return; } } SAFISH_CALL( go_accel(); af_driver->DrawLine(af_driver, color, itofix(x1+bmp->x_ofs), itofix(y1+bmp->y_ofs), itofix(x2+bmp->x_ofs), itofix(y2+bmp->y_ofs)); ); } /* vbeaf_rectfill: * Accelerated rectangle filling routine. */ static void vbeaf_rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color) { if (x2 < x1) { int tmp = x1; x1 = x2; x2 = tmp; } if (y2 < y1) { int tmp = y1; y1 = y2; y2 = tmp; } if (bmp->clip) { if (x1 < bmp->cl) x1 = bmp->cl; if (x2 >= bmp->cr) x2 = bmp->cr-1; if (x2 < x1) return; if (y1 < bmp->ct) y1 = bmp->ct; if (y2 >= bmp->cb) y2 = bmp->cb-1; if (y2 < y1) return; } SAFISH_CALL( go_accel(); switch (_drawing_mode) { case DRAW_MODE_SOLID: case DRAW_MODE_XOR: /* mono rectangle fill */ af_driver->DrawRect(af_driver, color, x1+bmp->x_ofs, y1+bmp->y_ofs, x2-x1+1, y2-y1+1); break; case DRAW_MODE_COPY_PATTERN: /* colored pattern rectangle fill */ prepare_color_pattern(bmp); af_driver->DrawColorPattRect(af_driver, x1+bmp->x_ofs, y1+bmp->y_ofs, x2-x1+1, y2-y1+1); break; case DRAW_MODE_SOLID_PATTERN: case DRAW_MODE_MASKED_PATTERN: /* mono pattern rectangle fill */ prepare_mono_pattern(bmp); af_driver->DrawPattRect(af_driver, color, 0, x1+bmp->x_ofs, y1+bmp->y_ofs, x2-x1+1, y2-y1+1); break; } ); } /* vbeaf_triangle: * Hardware accelerated triangle drawing function. */ static void vbeaf_triangle(BITMAP *bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color) { AF_TRAP trap; /* bounding box test */ if (bmp->clip) { if ((x1 < bmp->cl) || (x2 < bmp->cl) || (x3 < bmp->cl)) { _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color); return; } if ((y1 < bmp->ct) || (y2 < bmp->ct) || (y3 < bmp->ct)) { _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color); return; } if ((x1 >= bmp->cr) || (x2 >= bmp->cr) || (x3 >= bmp->cr)) { _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color); return; } if ((y1 >= bmp->cb) || (y2 >= bmp->cb) || (y3 >= bmp->cb)) { _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color); return; } } /* sort along the vertical axis */ #define TRI_SWAP(a, b) \ { \ int tmp = x##a; \ x##a = x##b; \ x##b = tmp; \ \ tmp = y##a; \ y##a = y##b; \ y##b = tmp; \ } if (y2 < y1) TRI_SWAP(1, 2); if (y3 < y1) { TRI_SWAP(1, 3); TRI_SWAP(2, 3); } else if (y3 < y2) TRI_SWAP(2, 3); SAFISH_CALL( go_accel(); if (y2 > y1) { /* draw the top half of the triangle as one trapezoid */ trap.y = y1+bmp->y_ofs; trap.count = y2-y1; trap.x1 = trap.x2 = itofix(x1+bmp->x_ofs); trap.slope1 = itofix(x2-x1) / (y2-y1); trap.slope2 = itofix(x3-x1) / (y3-y1); if (trap.slope1 < 0) trap.x1 += MIN(trap.slope1+itofix(1), 0); if (trap.slope2 < 0) trap.x2 += MIN(trap.slope2+itofix(1), 0); if (trap.slope1 > trap.slope2) trap.x1 += MAX(ABS(trap.slope1), itofix(1)); else trap.x2 += MAX(ABS(trap.slope2), itofix(1)); af_driver->DrawTrap(af_driver, color, &trap); if (y3 > y2) { /* draw the bottom half as a second trapezoid */ if (trap.slope1 < 0) trap.x1 -= MIN(trap.slope1+itofix(1), 0); if (trap.slope1 > trap.slope2) trap.x1 -= MAX(ABS(trap.slope1), itofix(1)); trap.count = y3-y2; trap.slope1 = itofix(x3-x2) / (y3-y2); if (trap.slope1 < 0) trap.x1 += MIN(trap.slope1+itofix(1), 0); if (trap.x1 > trap.x2) trap.x1 += MAX(ABS(trap.slope1), itofix(1)); af_driver->DrawTrap(af_driver, color, &trap); } } else if (y3 > y2) { /* we can draw the entire thing with a single trapezoid */ trap.y = y1+bmp->y_ofs; trap.count = y3-y2; trap.x1 = itofix(x2+bmp->x_ofs); trap.x2 = itofix(x1+bmp->x_ofs); trap.slope1 = itofix(x3-x2) / (y3-y2); trap.slope2 = (y3 > y1) ? (itofix(x3-x1) / (y3-y1)) : 0; if (trap.slope1 < 0) trap.x1 += MIN(trap.slope1+itofix(1), 0); if (trap.slope2 < 0) trap.x2 += MIN(trap.slope2+itofix(1), 0); if (trap.x1 > trap.x2) trap.x1 += MAX(ABS(trap.slope1), itofix(1)); else trap.x2 += MAX(ABS(trap.slope2), itofix(1)); af_driver->DrawTrap(af_driver, color, &trap); } ); } /* vbeaf_draw_glyph: * Monochrome text plotter. */ static void vbeaf_draw_glyph(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg) { AL_CONST unsigned char *data = glyph->dat; int w = glyph->w; int h = glyph->h; int stride = (w+7)/8; int d; /* give up if we can't draw this */ if ((x < bmp->cl) || (x+w >= bmp->cr) || ((w&7) && (bg >= 0))) { orig_draw_glyph(bmp, glyph, x, y, color, bg); return; } /* clip the top */ if (y < bmp->ct) { d = bmp->ct - y; h -= d; if (h <= 0) return; data += d*stride; y = bmp->ct; } /* clip the bottom */ if (y+h >= bmp->cb) { h = bmp->cb - y; if (h <= 0) return; } SAFE_CALL( /* set the mix mode */ if (bg >= 0) { af_driver->SetMix(af_driver, 0, 0); d = bg; } else { af_driver->SetMix(af_driver, 0, 4); d = 0; } /* draw the letter */ go_accel(); af_driver->PutMonoImage(af_driver, color, d, x+bmp->x_ofs, y+bmp->y_ofs, stride, 0, 0, stride*8, h, (unsigned char *)data); af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); } /* vbeaf_draw_sprite: * Accelerated sprite drawing routine. */ static void vbeaf_draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y) { int sx, sy, w, h; int pitch; if (((sprite->vtable == &_screen_vtable) && (af_driver->SrcTransBlt)) || ((sprite->vtable != &_screen_vtable) && (af_driver->SrcTransBltSys))) { /* this sprite can be drawn in hardware */ sx = sprite->x_ofs; sy = sprite->y_ofs; w = sprite->w; h = sprite->h; if (bmp->clip) { if (x < bmp->cl) { sx += bmp->cl-x; w -= bmp->cl-x; x = bmp->cl; } if (y < bmp->ct) { sy += bmp->ct-y; h -= bmp->ct-y; y = bmp->ct; } if (x+w > bmp->cr) w = bmp->cr-x; if (w <= 0) return; if (y+h > bmp->cb) h = bmp->cb-y; if (h <= 0) return; } if (sprite->vtable == &_screen_vtable) { /* hardware blit within the video memory */ SAFISH_CALL( go_accel(); af_driver->SrcTransBlt(af_driver, sx, sy, w, h, x+bmp->x_ofs, y+bmp->y_ofs, 0, sprite->vtable->mask_color); ); } else { /* hardware blit from system memory */ if (sprite->h > 1) pitch = (long)sprite->line[1] - (long)sprite->line[0]; else pitch = sprite->w; SAFE_CALL( go_accel(); af_driver->SrcTransBltSys(af_driver, sprite->line[0], pitch, sx, sy, w, h, x+bmp->x_ofs, y+bmp->y_ofs, 0, sprite->vtable->mask_color); ); } } else { /* have to use the original software version */ orig_draw_sprite(bmp, sprite, x, y); } } END_OF_STATIC_FUNCTION(vbeaf_draw_sprite); /* vbeaf_blit_from_memory: * Accelerated system memory -> vram blitting routine. */ static void vbeaf_blit_from_memory(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { int pitch; if (source->h > 1) pitch = (long)source->line[1] - (long)source->line[0]; else pitch = source->w; SAFE_CALL( go_accel(); af_driver->BitBltSys(af_driver, source->line[0], pitch, source_x, source_y, width, height, dest_x+dest->x_ofs, dest_y+dest->y_ofs, 0); ); } END_OF_STATIC_FUNCTION(vbeaf_blit_from_memory); /* vbeaf_blit_to_self: * Accelerated vram -> vram blitting routine. */ static void vbeaf_blit_to_self(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { SAFISH_CALL( go_accel(); af_driver->BitBlt(af_driver, source_x+source->x_ofs, source_y+source->y_ofs, width, height, dest_x+dest->x_ofs, dest_y+dest->y_ofs, 0); ); } /* vbeaf_masked_blit: * Accelerated masked blitting routine. */ static void vbeaf_masked_blit(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height) { int pitch; if ((source->vtable == &_screen_vtable) && (af_driver->SrcTransBlt)) { /* hardware blit within the video memory */ SAFISH_CALL( go_accel(); af_driver->SrcTransBlt(af_driver, source_x+source->x_ofs, source_y+source->y_ofs, width, height, dest_x+dest->x_ofs, dest_y+dest->y_ofs, 0, source->vtable->mask_color); ); } else if (af_driver->SrcTransBltSys) { /* hardware blit from system memory */ if (source->h > 1) pitch = (long)source->line[1] - (long)source->line[0]; else pitch = source->w; SAFE_CALL( go_accel(); af_driver->SrcTransBltSys(af_driver, source->line[0], pitch, source_x, source_y, width, height, dest_x+dest->x_ofs, dest_y+dest->y_ofs, 0, source->vtable->mask_color); ); } else { /* have to use the original software version */ orig_masked_blit(source, dest, source_x, source_y, dest_x, dest_y, width, height); } } /* vbeaf_clear_to_color: * Accelerated screen clear routine. */ static void vbeaf_clear_to_color(BITMAP *bitmap, int color) { SAFISH_CALL( go_accel(); if ((vbeaf_fg_mix != 0) || (vbeaf_bg_mix != 0)) af_driver->SetMix(af_driver, 0, 0); af_driver->DrawRect(af_driver, color, bitmap->cl+bitmap->x_ofs, bitmap->ct+bitmap->y_ofs, bitmap->cr-bitmap->cl, bitmap->cb-bitmap->ct); if ((vbeaf_fg_mix != 0) || (vbeaf_bg_mix != 0)) af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix); ); } #endif /* ifdef VBE/AF is cool on this platform */