1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Video driver using the VBE/AF 2.0 hardware accelerator API,
12  *      plus extensions added by the FreeBE/AF project.
13  *
14  *      This driver provides accelerated support for:
15  *
16  *       - scanline fills (solid, XOR, and patterned)
17  *       - area fills (solid, XOR, and patterned)
18  *       - line drawing (solid and XOR)
19  *       - triangle drawing (solid and XOR)
20  *       - monochrome character expansion
21  *       - blitting within the video memory
22  *       - masked blitting within the video memory
23  *       - blits from system memory
24  *       - masked blits from system memory
25  *       - hardware mouse cursors
26  *
27  *      The FreeBE/AF project (http://www.talula.demon.co.uk/freebe/)
28  *      has defined a number of API extensions, of which this driver
29  *      implements:
30  *
31  *       FAFEXT_INIT  - extension init and new driver relocation mechanism
32  *       FAFEXT_HWPTR - farptr access to video memory (no more Fat DS hack)
33  *       FAFEXT_LIBC  - exports a bunch of callback functions from libc
34  *       FAFEXT_PMODE - exports the SciTech pmode API callback functions
35  *
36  *      On the subject of VBE/AF in general:
37  *
38  *      Kendall Bennett and Tom Ryan of SciTech software deserve
39  *      significant thanks for coming up with such a magnificent API and
40  *      then helping me write this driver, after the VESA people (may they
41  *      be smitten with plagues of locusts and then develop subtle memory
42  *      leaks in their code :-) decided to charge stupid sums of money for
43  *      copies of the /AF specification. Unfortunately, SciTech have
44  *      subsequently abandoned VBE/AF in favour of a closed, proprietary
45  *      system called Nucleus. Ah well, I'm sure that this makes sense
46  *      for them in commercial terms, even if it is something of a
47  *      disappointment for us idealistic hacker types...
48  *
49  *      The problem with Nucleus is that the spec is only available under
50  *      NDA, so I cannot support it directly in Allegro. The plan,
51  *      therefore, is to write a Nucleus to VBE/AF wrapper driver.
52  *      This requires a few callback routines that stock VBE/AF doesn't
53  *      provide, hence the Nucleus-specific extensions in this file. It
54  *      doesn't provide direct Nucleus support, but hopefully will enable
55  *      someone (whether us or SciTech) to add that support in the future
56  *      via an external driver binary.
57  *
58  *      By Shawn Hargreaves.
59  *
60  *      See readme.txt for copyright information.
61  */
62 
63 
64 #include <string.h>
65 
66 #include "allegro.h"
67 
68 #if (defined ALLEGRO_DOS) || (defined ALLEGRO_LINUX_VBEAF)
69 
70 #include "allegro/internal/aintern.h"
71 
72 #ifdef ALLEGRO_INTERNAL_HEADER
73    #include ALLEGRO_INTERNAL_HEADER
74 #endif
75 
76 #if (defined ALLEGRO_DJGPP) && (!defined SCAN_DEPEND)
77    #include <crt0.h>
78    #include <sys/nearptr.h>
79    #include <sys/exceptn.h>
80 #endif
81 
82 
83 
84 /* main driver routines */
85 static BITMAP *vbeaf_init(int w, int h, int v_w, int v_h, int color_depth);
86 static void vbeaf_exit(BITMAP *b);
87 static void vbeaf_save(void);
88 static void vbeaf_restore(void);
89 static GFX_MODE_LIST *vbeaf_fetch_mode_list(void);
90 static void vbeaf_vsync(void);
91 static int vbeaf_scroll(int x, int y);
92 static void vbeaf_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync);
93 static int vbeaf_request_scroll(int x, int y);
94 static int vbeaf_poll_scroll(void);
95 static int vbeaf_set_mouse_sprite(BITMAP *sprite, int xfocus, int yfocus);
96 static int vbeaf_show_mouse(BITMAP *bmp, int x, int y);
97 static void vbeaf_hide_mouse(void);
98 static void vbeaf_move_mouse(int x, int y);
99 static void vbeaf_drawing_mode(void);
100 static int vbeaf_locate_driver(void);
101 static int vbeaf_lowlevel_init(void);
102 
103 
104 /* accelerated drawing functions */
105 static void vbeaf_hline(BITMAP *bmp, int x1, int y, int x2, int color);
106 static void vbeaf_vline_a(BITMAP *bmp, int x, int y1, int y2, int color);
107 static void vbeaf_vline_b(BITMAP *bmp, int x, int y1, int y2, int color);
108 static void vbeaf_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
109 static void vbeaf_rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
110 static void vbeaf_triangle(BITMAP *bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color);
111 static void vbeaf_draw_glyph(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg);
112 static void vbeaf_draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y);
113 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);
114 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);
115 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);
116 static void vbeaf_clear_to_color(BITMAP *bitmap, int color);
117 
118 
119 #ifdef ALLEGRO_DOS
120    static void vbeaf_move_mouse_end(void);
121    static void vbeaf_draw_sprite_end(void);
122    static void vbeaf_blit_from_memory_end(void);
123 #endif
124 
125 
126 /* original software drawing functions */
127 static void (*orig_vline)(BITMAP *bmp, int x, int y1, int y2, int color);
128 static void (*orig_hline)(BITMAP *bmp, int x1, int y, int x2, int color);
129 static void (*orig_line)(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
130 static void (*orig_rectfill)(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
131 static void (*orig_draw_glyph)(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg);
132 static void (*orig_draw_sprite)(BITMAP *bmp, BITMAP *sprite, int x, int y);
133 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);
134 
135 
136 static char vbeaf_desc[256] = EMPTY_STRING;
137 
138 
139 
140 /* the video driver structure */
141 GFX_DRIVER gfx_vbeaf =
142 {
143    GFX_VBEAF,
144    empty_string,
145    empty_string,
146    "VBE/AF",
147    vbeaf_init,
148    vbeaf_exit,
149    vbeaf_scroll,
150    vbeaf_vsync,
151    vbeaf_set_palette_range,
152    vbeaf_request_scroll,
153    vbeaf_poll_scroll,
154    NULL,                         /* enable triple buffer */
155    NULL, NULL, NULL, NULL,       /* no video bitmaps */
156    NULL, NULL,                   /* no system bitmaps */
157    NULL, NULL, NULL, NULL,       /* no hardware cursor (yet) */
158    NULL,                         /* no drawing mode hook */
159    vbeaf_save,
160    vbeaf_restore,
161    NULL,                         /* AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a)); */
162    vbeaf_fetch_mode_list,        /* fetch mode hook */
163    0, 0, FALSE, 0, 0, 0, 0, FALSE
164 };
165 
166 
167 
168 typedef struct AF_FIX_POINT      /* fixed point coordinate pair */
169 {
170    fixed x;
171    fixed y;
172 } AF_FIX_POINT;
173 
174 
175 
176 typedef struct AF_TRAP           /* trapezium information block */
177 {
178    long y;
179    long count;
180    fixed x1;
181    fixed x2;
182    fixed slope1;
183    fixed slope2;
184 } AF_TRAP;
185 
186 
187 
188 typedef struct AF_CURSOR         /* hardware cursor description */
189 {
190    unsigned long xorMask[32];
191    unsigned long andMask[32];
192    unsigned long hotx;
193    unsigned long hoty;
194 } AF_CURSOR;
195 
196 
197 
198 typedef struct AF_PALETTE        /* color value (not in Allegro order) */
199 {
200    unsigned char blue;
201    unsigned char green;
202    unsigned char red;
203    unsigned char alpha;
204 } AF_PALETTE;
205 
206 
207 
208 #ifdef ALLEGRO_GCC
209    #define __PACKED__   __attribute__ ((packed))
210 #else
211    #define __PACKED__
212 #endif
213 
214 #ifdef ALLEGRO_WATCOM
215    #pragma pack (1)
216 #endif
217 
218 
219 
220 typedef struct AF_MODE_INFO      /* mode information structure */
221 {
222    unsigned short Attributes              __PACKED__;
223    unsigned short XResolution             __PACKED__;
224    unsigned short YResolution             __PACKED__;
225    unsigned short BytesPerScanLine        __PACKED__;
226    unsigned short BitsPerPixel            __PACKED__;
227    unsigned short MaxBuffers              __PACKED__;
228    unsigned char  RedMaskSize;
229    unsigned char  RedFieldPosition;
230    unsigned char  GreenMaskSize;
231    unsigned char  GreenFieldPosition;
232    unsigned char  BlueMaskSize;
233    unsigned char  BlueFieldPosition;
234    unsigned char  RsvdMaskSize;
235    unsigned char  RsvdFieldPosition;
236    unsigned short MaxBytesPerScanLine     __PACKED__;
237    unsigned short MaxScanLineWidth        __PACKED__;
238 
239    /* VBE/AF 2.0 extensions */
240    unsigned short LinBytesPerScanLine     __PACKED__;
241    unsigned char  BnkMaxBuffers;
242    unsigned char  LinMaxBuffers;
243    unsigned char  LinRedMaskSize;
244    unsigned char  LinRedFieldPosition;
245    unsigned char  LinGreenMaskSize;
246    unsigned char  LinGreenFieldPosition;
247    unsigned char  LinBlueMaskSize;
248    unsigned char  LinBlueFieldPosition;
249    unsigned char  LinRsvdMaskSize;
250    unsigned char  LinRsvdFieldPosition;
251    unsigned long  MaxPixelClock           __PACKED__;
252    unsigned long  VideoCapabilities       __PACKED__;
253    unsigned short VideoMinXScale          __PACKED__;
254    unsigned short VideoMinYScale          __PACKED__;
255    unsigned short VideoMaxXScale          __PACKED__;
256    unsigned short VideoMaxYScale          __PACKED__;
257 
258    unsigned char  reserved[76];
259 
260 } AF_MODE_INFO;
261 
262 
263 
264 #define DC  struct AF_DRIVER *dc
265 
266 
267 
268 typedef struct AF_DRIVER         /* VBE/AF driver structure */
269 {
270    /* driver header */
271    char           Signature[12];
272    unsigned long  Version                 __PACKED__;
273    unsigned long  DriverRev               __PACKED__;
274    char           OemVendorName[80];
275    char           OemCopyright[80];
276    unsigned short *AvailableModes         __PACKED__;
277    unsigned long  TotalMemory             __PACKED__;
278    unsigned long  Attributes              __PACKED__;
279    unsigned long  BankSize                __PACKED__;
280    unsigned long  BankedBasePtr           __PACKED__;
281    unsigned long  LinearSize              __PACKED__;
282    unsigned long  LinearBasePtr           __PACKED__;
283    unsigned long  LinearGranularity       __PACKED__;
284    unsigned short *IOPortsTable           __PACKED__;
285    unsigned long  IOMemoryBase[4]         __PACKED__;
286    unsigned long  IOMemoryLen[4]          __PACKED__;
287    unsigned long  LinearStridePad         __PACKED__;
288    unsigned short PCIVendorID             __PACKED__;
289    unsigned short PCIDeviceID             __PACKED__;
290    unsigned short PCISubSysVendorID       __PACKED__;
291    unsigned short PCISubSysID             __PACKED__;
292    unsigned long  Checksum                __PACKED__;
293    unsigned long  res2[6]                 __PACKED__;
294 
295    /* near pointers mapped by the application */
296    void           *IOMemMaps[4]           __PACKED__;
297    void           *BankedMem              __PACKED__;
298    void           *LinearMem              __PACKED__;
299    unsigned long  res3[5]                 __PACKED__;
300 
301    /* driver state variables */
302    unsigned long  BufferEndX              __PACKED__;
303    unsigned long  BufferEndY              __PACKED__;
304    unsigned long  OriginOffset            __PACKED__;
305    unsigned long  OffscreenOffset         __PACKED__;
306    unsigned long  OffscreenStartY         __PACKED__;
307    unsigned long  OffscreenEndY           __PACKED__;
308    unsigned long  res4[10]                __PACKED__;
309 
310    /* relocatable 32 bit bank switch routine, for Windows (ugh!) */
311    unsigned long  SetBank32Len            __PACKED__;
312    void           *SetBank32              __PACKED__;
313 
314    /* callback functions provided by the application */
315    void           *Int86                  __PACKED__;
316    void           *CallRealMode           __PACKED__;
317 
318    /* main driver setup routine */
319    void           *InitDriver             __PACKED__;
320 
321    /* VBE/AF 1.0 asm interface (obsolete and not supported by Allegro) */
322    void           *af10Funcs[40]          __PACKED__;
323 
324    /* VBE/AF 2.0 extensions */
325    void           *PlugAndPlayInit        __PACKED__;
326 
327    /* FreeBE/AF extension query function */
328    void           *(*OemExt)(DC, unsigned long id);
329 
330    /* extension hook for implementing additional VESA interfaces */
331    void           *SupplementalExt        __PACKED__;
332 
333    /* device driver functions */
334    long  (*GetVideoModeInfo)(DC, short mode, AF_MODE_INFO *modeInfo);
335    long  (*SetVideoMode)(DC, short mode, long virtualX, long virtualY, long *bytesPerLine, int numBuffers, void *crtc);
336    void  (*RestoreTextMode)(DC);
337    long  (*GetClosestPixelClock)(DC, short mode, unsigned long pixelClock);
338    void  (*SaveRestoreState)(DC, int subfunc, void *saveBuf);
339    void  (*SetDisplayStart)(DC, long x, long y, long waitVRT);
340    void  (*SetActiveBuffer)(DC, long index);
341    void  (*SetVisibleBuffer)(DC, long index, long waitVRT);
342    int   (*GetDisplayStartStatus)(DC);
343    void  (*EnableStereoMode)(DC, int enable);
344    void  (*SetPaletteData)(DC, AF_PALETTE *pal, long num, long index, long waitVRT);
345    void  (*SetGammaCorrectData)(DC, AF_PALETTE *pal, long num, long index);
346    void  (*SetBank)(DC, long bank);
347 
348    /* hardware cursor functions */
349    void  (*SetCursor)(DC, AF_CURSOR *cursor);
350    void  (*SetCursorPos)(DC, long x, long y);
351    void  (*SetCursorColor)(DC, unsigned char red, unsigned char green, unsigned char blue);
352    void  (*ShowCursor)(DC, long visible);
353 
354    /* 2D rendering functions */
355    void  (*WaitTillIdle)(DC);
356    void  (*EnableDirectAccess)(DC);
357    void  (*DisableDirectAccess)(DC);
358    void  (*SetMix)(DC, long foreMix, long backMix);
359    void  (*Set8x8MonoPattern)(DC, unsigned char *pattern);
360    void  (*Set8x8ColorPattern)(DC, int index, unsigned long *pattern);
361    void  (*Use8x8ColorPattern)(DC, int index);
362    void  (*SetLineStipple)(DC, unsigned short stipple);
363    void  (*SetLineStippleCount)(DC, unsigned long count);
364    void  (*SetClipRect)(DC, long minx, long miny, long maxx, long maxy);
365    void  (*DrawScan)(DC, long color, long y, long x1, long x2);
366    void  (*DrawPattScan)(DC, long foreColor, long backColor, long y, long x1, long x2);
367    void  (*DrawColorPattScan)(DC, long y, long x1, long x2);
368    void  (*DrawScanList)(DC, unsigned long color, long y, long length, short *scans);
369    void  (*DrawPattScanList)(DC, unsigned long foreColor, unsigned long backColor, long y, long length, short *scans);
370    void  (*DrawColorPattScanList)(DC, long y, long length, short *scans);
371    void  (*DrawRect)(DC, unsigned long color, long left, long top, long width, long height);
372    void  (*DrawPattRect)(DC, unsigned long foreColor, unsigned long backColor, long left, long top, long width, long height);
373    void  (*DrawColorPattRect)(DC, long left, long top, long width, long height);
374    void  (*DrawLine)(DC, unsigned long color, fixed x1, fixed y1, fixed x2, fixed y2);
375    void  (*DrawStippleLine)(DC, unsigned long foreColor, unsigned long backColor, fixed x1, fixed y1, fixed x2, fixed y2);
376    void  (*DrawTrap)(DC, unsigned long color, AF_TRAP *trap);
377    void  (*DrawTri)(DC, unsigned long color, AF_FIX_POINT *v1, AF_FIX_POINT *v2, AF_FIX_POINT *v3, fixed xOffset, fixed yOffset);
378    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);
379    void  (*PutMonoImage)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, unsigned char *image);
380    void  (*PutMonoImageLin)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imageOfs);
381    void  (*PutMonoImageBM)(DC, long foreColor, long backColor, long dstX, long dstY, long byteWidth, long srcX, long srcY, long width, long height, long imagePhysAddr);
382    void  (*BitBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op);
383    void  (*BitBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
384    void  (*BitBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
385    void  (*BitBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op);
386    void  (*SrcTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
387    void  (*SrcTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
388    void  (*SrcTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
389    void  (*SrcTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
390    void  (*DstTransBlt)(DC, long left, long top, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
391    void  (*DstTransBltSys)(DC, void *srcAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
392    void  (*DstTransBltLin)(DC, long srcOfs, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
393    void  (*DstTransBltBM)(DC, long srcPhysAddr, long srcPitch, long srcLeft, long srcTop, long width, long height, long dstLeft, long dstTop, long op, unsigned long transparent);
394    void  (*StretchBlt)(DC, long srcLeft, long srcTop, long srcWidth, long srcHeight, long dstLeft, long dstTop, long dstWidth, long dstHeight, long flags, long op);
395    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);
396    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);
397    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);
398    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);
399    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);
400    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);
401    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);
402    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);
403    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);
404    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);
405    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);
406 
407    /* hardware video functions */
408    void  (*SetVideoInput)(DC, long width, long height, long format);
409    void *(*SetVideoOutput)(DC, long left, long top, long width, long height);
410    void  (*StartVideoFrame)(DC);
411    void  (*EndVideoFrame)(DC);
412 
413 } AF_DRIVER;
414 
415 
416 
417 #undef DC
418 
419 
420 
421 /* FreeBE/AF API extensions use 32 bit magic numbers */
422 #define FAF_ID(a,b,c,d)    ((a<<24) | (b<<16) | (c<<8) | d)
423 
424 
425 
426 /* ID code and magic return value for initialising the extensions */
427 #define FAFEXT_INIT     FAF_ID('I','N','I','T')
428 #define FAFEXT_MAGIC    FAF_ID('E','X', 0,  0)
429 
430 
431 
432 /* function exporting extensions (needed for Nucleus compatibility) */
433 #define FAFEXT_LIBC     FAF_ID('L','I','B','C')
434 #define FAFEXT_PMODE    FAF_ID('P','M','O','D')
435 
436 
437 
438 /* extension providing a hardware-specific way to access video memory */
439 #define FAFEXT_HWPTR    FAF_ID('H','P','T','R')
440 
441 
442 typedef struct FAF_HWPTR
443 {
444    int sel;
445    unsigned long offset;
446 } FAF_HWPTR;
447 
448 
449 typedef struct FAF_HWPTR_DATA
450 {
451    FAF_HWPTR IOMemMaps[4];
452    FAF_HWPTR BankedMem;
453    FAF_HWPTR LinearMem;
454 } FAF_HWPTR_DATA;
455 
456 
457 
458 #ifdef ALLEGRO_LINUX
459 
460    #include <sys/stat.h>
461    #include <sys/mman.h>
462 
463    /* quick and dirty Linux emulation of the DOS memory mapping routines */
464    #define _create_linear_mapping(_addr, _base, _len)       \
465    ({                                                       \
466       (_addr)->base = _base;                                \
467       (_addr)->size = _len;                                 \
468       (_addr)->perms = PROT_READ | PROT_WRITE;              \
469       __al_linux_map_memory(_addr);                         \
470    })
471 
472    #define _remove_linear_mapping(_addr)                    \
473    {                                                        \
474       if ((_addr)->data)                                    \
475 	 __al_linux_unmap_memory(_addr);                    \
476    }
477 
478    #define _create_selector(sel, addr, len)  -1
479 
480    #define _remove_selector(sel)
481 
482    #define MMAP      struct MAPPED_MEMORY
483    #define NOMM      { 0, 0, 0, 0 }
484    #define MVAL(a)   a.data
485 
486 #else
487 
488    /* DOS version */
489    #define MMAP      unsigned long
490    #define NOMM      0
491    #define MVAL(a)   (void *)((a)-__djgpp_base_address)
492 
493 #endif
494 
495 
496 
497 static AF_DRIVER *af_driver = NULL;    /* the VBE/AF driver */
498 
499 void *_accel_driver = NULL;            /* externally visible driver pointer */
500 
501 int _accel_active = FALSE;             /* is the accelerator busy? */
502 
503 void *_accel_set_bank;                 /* shortcuts to driver functions */
504 void *_accel_idle;
505 
506 static int in_af_mode = FALSE;         /* true if VBE/AF is in use */
507 
508 static int faf_id = FALSE;             /* true if FreeBE/AF detected */
509 static int faf_ext = 0;                /* FreeBE/AF extensions version */
510 
511 static FAF_HWPTR_DATA *faf_farptr;     /* FreeBE/AF farptr data */
512 
513 static int vbeaf_xscroll = 0;          /* current display start address */
514 static int vbeaf_yscroll = 0;
515 
516 static int vbeaf_fg_mix = 0;           /* current hardware mix mode */
517 static int vbeaf_bg_mix = 0;
518 
519 static int vbeaf_cur_c1 = -1;          /* hardware cursor colors */
520 static int vbeaf_cur_c2 = -1;
521 
522 static BITMAP *vbeaf_cur_bmp = NULL;   /* bitmap showing the cursor */
523 
524 static int vbeaf_cur_x;                /* cursor position */
525 static int vbeaf_cur_y;
526 static int vbeaf_cur_on;
527 
528 static BITMAP *vbeaf_pattern = NULL;   /* currently loaded pattern bitmap */
529 
530 static MMAP af_memmap[4] = { NOMM, NOMM, NOMM, NOMM };
531 static MMAP af_banked_mem = NOMM;
532 static MMAP af_linear_mem = NOMM;
533 
534 #ifdef ALLEGRO_DOS
535    static int vbeaf_nearptr = FALSE;   /* did we enable nearptrs ourselves? */
536 #endif
537 
538 #ifdef ALLEGRO_LINUX
539    int _vbeaf_selector = 0;            /* Linux version of __djgpp_ds_alias */
540 #endif
541 
542 static int saved_mode;                 /* state info for console switches */
543 static int saved_vw;
544 static int saved_vh;
545 static int saved_wret;
546 
547 extern void _af_int86(void), _af_call_rm(void), _af_wrapper(void), _af_wrapper_end(void);
548 
549 
550 
551 #ifdef ALLEGRO_DJGPP
552 
553    /* djgpp wrapper to disable exceptions during critical operations */
554    #define SAFE_CALL(FUNC)                \
555    {                                      \
556       int _ds, _es, _ss;                  \
557 					  \
558       asm volatile (                      \
559 	 " movw %%ds, %w0 ; "             \
560 	 " movw %%es, %w1 ; "             \
561 	 " movw %%ss, %w2 ; "             \
562 	 " movw %w3, %%ds ; "             \
563 	 " movw %w3, %%es ; "             \
564 	 " movw %w3, %%ss ; "             \
565 					  \
566       : "=&q" (_ds),                      \
567 	"=&q" (_es),                      \
568 	"=&q" (_ss)                       \
569 					  \
570       : "q" (__djgpp_ds_alias)            \
571       );                                  \
572 					  \
573       FUNC                                \
574 					  \
575       asm volatile (                      \
576 	 "movw %w0, %%ds ; "              \
577 	 "movw %w1, %%es ; "              \
578 	 "movw %w2, %%ss ; "              \
579       :                                   \
580       : "q" (_ds),                        \
581 	"q" (_es),                        \
582 	"q" (_ss)                         \
583       );                                  \
584    }
585 
586    #define SAFISH_CALL(FUNC)  FUNC
587 
588 #elif defined ALLEGRO_LINUX
589 
590    /* Linux wrapper to disable console switches during critical operations */
591    #define SAFE_CALL(FUNC)                \
592    {                                      \
593       __al_linux_switching_blocked++;     \
594 					  \
595       FUNC                                \
596 					  \
597       __al_linux_release_bitmap(NULL);    \
598    }
599 
600    #define SAFISH_CALL(FUNC)  SAFE_CALL(FUNC)
601 
602 #else
603 
604    #define SAFE_CALL(FUNC)    FUNC
605    #define SAFISH_CALL(FUNC)  FUNC
606 
607 #endif
608 
609 
610 
611 /* bswap:
612  *  Toggles the endianess of a 32 bit integer.
613  */
bswap(unsigned long n)614 static unsigned long bswap(unsigned long n)
615 {
616    unsigned long a = n & 0xFF;
617    unsigned long b = (n>>8) & 0xFF;
618    unsigned long c = (n>>16) & 0xFF;
619    unsigned long d = (n>>24) & 0xFF;
620 
621    return (a<<24) | (b<<16) | (c<<8) | d;
622 }
623 
624 
625 
626 /* call_vbeaf_asm:
627  *  Calls a VBE/AF function using the version 1.0 style asm interface.
628  */
call_vbeaf_asm(void * proc)629 static int call_vbeaf_asm(void *proc)
630 {
631    int ret;
632 
633    proc = (void *)((long)af_driver + (long)proc);
634 
635    #ifdef ALLEGRO_GCC
636 
637       /* use gcc-style inline asm */
638       asm (
639 	 " pushl %%ebx ; "
640 	 " movl %%ecx, %%ebx ; "
641 	 " call *%%edx ; "
642 	 " popl %%ebx ; "
643 
644       : "=&a" (ret)                       /* return value in eax */
645 
646       : "c" (af_driver),                  /* VBE/AF driver in ds:ebx */
647 	"d" (proc)                        /* function ptr in edx */
648 
649       : "memory"                          /* assume everything is clobbered */
650       );
651 
652    #elif defined ALLEGRO_WATCOM
653 
654       /* use Watcom-style inline asm */
655       {
656 	 int _af(void *func, AF_DRIVER *driver);
657 
658 	 #pragma aux _af =                \
659 	    " call esi "                  \
660 					  \
661 	 parm [esi] [ebx]                 \
662 	 modify [ecx edx edi]             \
663 	 value [eax];
664 
665 	 ret = _af(proc, af_driver);
666       }
667 
668    #else
669 
670       /* don't know what to do on this compiler */
671       ret = -1;
672 
673    #endif
674 
675    return ret;
676 }
677 
678 
679 
680 /* vbeaf_no_wait:
681  *  Dummy wait-till-idle routine for non-accelerated drivers.
682  */
vbeaf_no_wait(void)683 static void vbeaf_no_wait(void)
684 {
685 }
686 
687 END_OF_STATIC_FUNCTION(vbeaf_no_wait);
688 
689 
690 
691 /* load_vbeaf_driver:
692  *  Tries to load the specified VBE/AF driver file, returning TRUE on
693  *  success. Allocates memory and reads the driver into it.
694  */
load_vbeaf_driver(AL_CONST char * filename)695 static int load_vbeaf_driver(AL_CONST char *filename)
696 {
697    long size;
698    PACKFILE *f;
699 
700    #ifdef ALLEGRO_LINUX
701 
702       /* on Linux. be paranoid and insist that vbeaf.drv belongs to root */
703       char tmp[128];
704       struct stat s;
705 
706       if (stat(uconvert_toascii(filename, tmp), &s) != 0)
707 	 return 0;
708 
709       if ((s.st_uid != 0) || (s.st_mode & (S_IWGRP | S_IWOTH))) {
710 	 uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("%s must only be writeable by root"), filename);
711 	 return -1;
712       }
713 
714       size = s.st_size;
715       if (size <= 0)
716 	 return 0;
717 
718    #else
719 
720       /* simple version for other platforms */
721       size = file_size_ex(filename);
722       if (size <= 0)
723 	 return 0;
724 
725    #endif
726 
727    f = pack_fopen(filename, F_READ);
728    if (!f)
729       return 0;
730 
731    af_driver = _accel_driver = _AL_MALLOC(size);
732 
733    if (pack_fread(af_driver, size, f) != size) {
734       _AL_FREE(af_driver);
735       af_driver = _accel_driver = NULL;
736       return 0;
737    }
738 
739    pack_fclose(f);
740 
741    LOCK_DATA(af_driver, size);
742 
743    return 1;
744 }
745 
746 
747 
748 /* initialise_freebeaf_extensions:
749  *  Prepares the FreeBE/AF extension functions.
750  */
initialise_freebeaf_extensions(void)751 static void initialise_freebeaf_extensions(void)
752 {
753    typedef unsigned long (*EXT_INIT_FUNC)(AF_DRIVER *af, unsigned long id);
754    EXT_INIT_FUNC ext_init;
755    unsigned long magic;
756    int v1, v2;
757 
758    #ifdef ALLEGRO_DOS
759       void *ptr;
760    #endif
761 
762    /* safety check */
763    if (!af_driver->OemExt) {
764       faf_ext = 0;
765       return;
766    }
767 
768    /* call the extension init function */
769    ext_init = (EXT_INIT_FUNC)((long)af_driver + (long)af_driver->OemExt);
770 
771    magic = ext_init(af_driver, FAFEXT_INIT);
772 
773    /* check that it returned a nice magic number */
774    v1 = (magic>>8)&0xFF;
775    v2 = magic&0xFF;
776 
777    if (((magic&0xFFFF0000) != FAFEXT_MAGIC) || (!uisdigit(v1)) || (!uisdigit(v2))) {
778       faf_ext = 0;
779       return;
780    }
781 
782    faf_ext = (v1-'0')*10 + (v2-'0');
783 
784    /* export libc and pmode functions if the driver wants them */
785    #ifdef ALLEGRO_DOS
786 
787       ptr = af_driver->OemExt(af_driver, FAFEXT_LIBC);
788       if (ptr)
789 	 _fill_vbeaf_libc_exports(ptr);
790 
791       ptr = af_driver->OemExt(af_driver, FAFEXT_PMODE);
792       if (ptr)
793 	 _fill_vbeaf_pmode_exports(ptr);
794 
795    #endif
796 }
797 
798 
799 
800 /* initialise_vbeaf_driver:
801  *  Sets up the DPMI memory mappings required by the VBE/AF driver,
802  *  returning zero on success.
803  */
initialise_vbeaf_driver(void)804 static int initialise_vbeaf_driver(void)
805 {
806    int c;
807 
808    #ifdef ALLEGRO_DJGPP
809 
810       /* query driver for the FreeBE/AF farptr extension */
811       if (faf_ext > 0)
812 	 faf_farptr = af_driver->OemExt(af_driver, FAFEXT_HWPTR);
813       else
814 	 faf_farptr = NULL;
815 
816    #else
817 
818       /* don't use farptr on any other platforms */
819       faf_farptr = NULL;
820 
821    #endif
822 
823    #ifdef ALLEGRO_DOS
824 
825       if (faf_farptr) {
826 	 /* use farptr access */
827 	 for (c=0; c<4; c++) {
828 	    faf_farptr->IOMemMaps[c].sel = 0;
829 	    faf_farptr->IOMemMaps[c].offset = 0;
830 	 }
831 
832 	 faf_farptr->BankedMem.sel = 0;
833 	 faf_farptr->BankedMem.offset = 0;
834 
835 	 faf_farptr->LinearMem.sel = 0;
836 	 faf_farptr->LinearMem.offset = 0;
837 
838 	 vbeaf_nearptr = FALSE;
839       }
840       else {
841 	 /* enable nearptr access */
842 	 if (_crt0_startup_flags & _CRT0_FLAG_NEARPTR) {
843 	    vbeaf_nearptr = FALSE;
844 	 }
845 	 else {
846 	    if (__djgpp_nearptr_enable() == 0)
847 	       return -2;
848 
849 	    vbeaf_nearptr = TRUE;
850 	 }
851       }
852 
853    #endif
854 
855    /* create mapping for MMIO ports */
856    for (c=0; c<4; c++) {
857       if (af_driver->IOMemoryBase[c]) {
858 	 if (_create_linear_mapping(af_memmap+c, af_driver->IOMemoryBase[c],
859 				    af_driver->IOMemoryLen[c]) != 0)
860 	    return -1;
861 
862 	 if (faf_farptr) {
863 	    /* farptr IO mapping */
864 	    if (_create_selector(&faf_farptr->IOMemMaps[c].sel, af_memmap[c],
865 				 af_driver->IOMemoryLen[c]) != 0) {
866 	       _remove_linear_mapping(af_memmap+c);
867 	       return -1;
868 	    }
869 	    faf_farptr->IOMemMaps[c].offset = 0;
870 	    af_driver->IOMemMaps[c] = NULL;
871 	 }
872 	 else {
873 	    /* nearptr IO mapping */
874 	    af_driver->IOMemMaps[c] = MVAL(af_memmap[c]);
875 	 }
876       }
877    }
878 
879    /* create mapping for banked video RAM */
880    if (af_driver->BankedBasePtr) {
881       if (_create_linear_mapping(&af_banked_mem, af_driver->BankedBasePtr, 0x10000) != 0)
882 	 return -1;
883 
884       if (faf_farptr) {
885 	 /* farptr banked vram mapping */
886 	 if (_create_selector(&faf_farptr->BankedMem.sel, af_banked_mem, 0x10000) != 0) {
887 	    _remove_linear_mapping(&af_banked_mem);
888 	    return -1;
889 	 }
890 	 faf_farptr->BankedMem.offset = 0;
891 	 af_driver->BankedMem = NULL;
892       }
893       else {
894 	 /* nearptr banked vram mapping */
895 	 af_driver->BankedMem = MVAL(af_banked_mem);
896       }
897    }
898 
899    /* create mapping for linear video RAM */
900    if (af_driver->LinearBasePtr) {
901       if (_create_linear_mapping(&af_linear_mem, af_driver->LinearBasePtr, af_driver->LinearSize*1024) != 0)
902 	 return -1;
903 
904       if (faf_farptr) {
905 	 /* farptr linear vram mapping */
906 	 if (_create_selector(&faf_farptr->LinearMem.sel, af_linear_mem, af_driver->LinearSize*1024) != 0) {
907 	    _remove_linear_mapping(&af_linear_mem);
908 	    return -1;
909 	 }
910 	 faf_farptr->LinearMem.offset = 0;
911 	 af_driver->LinearMem = NULL;
912       }
913       else {
914 	 /* nearptr linear vram mapping */
915 	 af_driver->LinearMem  = MVAL(af_linear_mem);
916       }
917    }
918 
919    /* callback functions: why are these needed? ugly, IMHO */
920    af_driver->Int86 = _af_int86;
921    af_driver->CallRealMode = _af_call_rm;
922 
923    return 0;
924 }
925 
926 
927 
928 /* find_vbeaf_mode:
929  *  Tries to find a VBE/AF mode number for the specified screen size.
930  */
find_vbeaf_mode(int w,int h,int v_w,int v_h,int color_depth,AF_MODE_INFO * mode_info)931 static int find_vbeaf_mode(int w, int h, int v_w, int v_h, int color_depth, AF_MODE_INFO *mode_info)
932 {
933    unsigned short *mode;
934 
935    /* search the list of modes */
936    for (mode = af_driver->AvailableModes; *mode != 0xFFFF; mode++) {
937 
938       /* retrieve the mode information block */
939       if (af_driver->GetVideoModeInfo(af_driver, *mode, mode_info) == 0) {
940 
941 	 /* check size and color depth */
942 	 if ((mode_info->XResolution == w) &&
943 	     (mode_info->YResolution == h) &&
944 	     (mode_info->BitsPerPixel == color_depth) &&
945 	     (mode_info->MaxScanLineWidth >= v_w)) {
946 
947 	    /* make sure the mode supports scrolling */
948 	    if ((v_w > w) || (v_h > h)) {
949 	       if (!(mode_info->Attributes & 2)) {
950 		  ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Hardware scrolling not supported"));
951 		  return 0;
952 	       }
953 	    }
954 
955 	    /* if it isn't FreeBE/AF, it must be UniVBE, so if we don't
956 	     * have hardware acceleration we may as well just fail this
957 	     * call and use VBE 3.0 instead.
958 	     */
959 	    if ((!(mode_info->Attributes & 16)) && (!faf_id)) {
960 	       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Hardware acceleration not available"));
961 	       return 0;
962 	    }
963 
964 	    return *mode;
965 	 }
966       }
967    }
968 
969    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Resolution not supported"));
970    return 0;
971 }
972 
973 
974 
975 /* set_vbeaf_mode:
976  *  Selects a VBE/AF graphics mode.
977  */
set_vbeaf_mode(int mode,int w,int h,int v_w,int v_h,int * width,int * scrollable)978 static int set_vbeaf_mode(int mode, int w, int h, int v_w, int v_h, int *width, int *scrollable)
979 {
980    long wret = *width;
981    int ret;
982 
983    if (gfx_vbeaf.linear)
984       mode |= 0x4000;
985 
986    /* try to set a large virtual screen */
987    mode |= 0x1000;
988    *scrollable = TRUE;
989 
990    saved_mode = mode;
991    saved_vw = v_w;
992    saved_vh = v_h;
993    saved_wret = wret;
994 
995    ret = af_driver->SetVideoMode(af_driver, mode, v_w, v_h, &wret, 1, NULL);
996 
997    if ((ret != 0) && (v_w <= w) && (v_h <= h)) {
998       /* if that didn't work, try to set a non-scrolling framebuffer */
999       mode &= ~0x1000;
1000       *scrollable = FALSE;
1001 
1002       saved_mode = mode;
1003       saved_wret = wret;
1004 
1005       ret = af_driver->SetVideoMode(af_driver, mode, v_w, v_h, &wret, 1, NULL);
1006    }
1007 
1008    *width = wret;
1009    return ret;
1010 }
1011 
1012 
1013 
1014 /* vbeaf_locate_driver:
1015  *  locates and loads a VBE/AF driver.
1016  */
vbeaf_locate_driver(void)1017 static int vbeaf_locate_driver(void)
1018 {
1019    static char *possible_filenames[] =
1020    {
1021    #ifdef ALLEGRO_DOS
1022       "c:\\vbeaf.drv",
1023    #else
1024       "/usr/local/lib/vbeaf.drv",
1025       "/usr/lib/vbeaf.drv",
1026       "/lib/vbeaf.drv",
1027       "/vbeaf.drv",
1028    #endif
1029       NULL
1030    };
1031 
1032    char filename[1024], tmp1[1024], tmp2[128];
1033    AL_CONST char *p;
1034    int ret, i, attrib;
1035 
1036    /* look for driver in the config file location */
1037    p = get_config_string(uconvert_ascii("graphics", tmp1), uconvert_ascii("vbeaf_driver", tmp2), NULL);
1038 
1039    if ((p) && (ugetc(p))) {
1040       ustrzcpy(filename, sizeof(filename), p);
1041 
1042       if (ugetc(get_filename(filename)) == 0) {
1043 	 append_filename(filename, filename, uconvert_ascii("vbeaf.drv", tmp1), sizeof(filename));
1044       }
1045       else {
1046 	 if (file_exists(filename, FA_DIREC, &attrib)) {
1047 	    if (attrib & FA_DIREC)
1048 	       append_filename(filename, filename, uconvert_ascii("vbeaf.drv", tmp1), sizeof(filename));
1049 	 }
1050       }
1051 
1052       ret = load_vbeaf_driver(filename);
1053       if (ret)
1054 	 goto found_it;
1055    }
1056 
1057    /* look for driver in the same directory as the program */
1058    get_executable_name(tmp1, sizeof(tmp1));
1059    replace_filename(filename, tmp1, uconvert_ascii("vbeaf.drv", tmp2), sizeof(filename));
1060    ret = load_vbeaf_driver(filename);
1061    if (ret)
1062       goto found_it;
1063 
1064    /* look for driver in the default location */
1065    for (i=0; possible_filenames[i]; i++) {
1066       ret = load_vbeaf_driver(uconvert_ascii(possible_filenames[i], tmp1));
1067       if (ret)
1068 	 goto found_it;
1069    }
1070 
1071    /* check the environment for a location */
1072    p = getenv("VBEAF_PATH");
1073    if (p) {
1074       append_filename(filename, uconvert_ascii(p, tmp1), uconvert_ascii("vbeaf.drv", tmp2), sizeof(filename));
1075       ret = load_vbeaf_driver(filename);
1076       if (ret)
1077 	 goto found_it;
1078    }
1079 
1080    /* oops, no driver */
1081    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can't find VBEAF.DRV"));
1082    ret = FALSE;
1083 
1084    /* got it! */
1085    found_it:
1086 
1087    return ret;
1088 }
1089 
1090 
1091 
1092 /*  vbeaf_lowlevel_init:
1093  *   loads the VBE/AF driver and initializes it.
1094  */
vbeaf_lowlevel_init(void)1095 static int vbeaf_lowlevel_init(void)
1096 {
1097    int ret;
1098 
1099    /* check the driver ID string */
1100    if (strcmp(af_driver->Signature, "VBEAF.DRV") != 0) {
1101       vbeaf_exit(NULL);
1102       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Bad VBE/AF driver ID string"));
1103       return FALSE;
1104    }
1105 
1106    /* check the VBE/AF version number */
1107    if (af_driver->Version < 0x200) {
1108       vbeaf_exit(NULL);
1109       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Obsolete VBE/AF version (need 2.0 or greater)"));
1110       return FALSE;
1111    }
1112 
1113    /* to run on Linux, we need to be God */
1114    #ifdef ALLEGRO_LINUX
1115 
1116       if (!__al_linux_have_ioperms) {
1117 	 vbeaf_exit(NULL);
1118 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("This driver needs root privileges"));
1119 	 return FALSE;
1120       }
1121 
1122       _vbeaf_selector = _default_ds();
1123 
1124    #endif
1125 
1126    /* detect and initialise the FreeBE/AF extensions */
1127    if (strstr(af_driver->OemVendorName, "FreeBE")) {
1128       faf_id = TRUE;
1129       initialise_freebeaf_extensions();
1130    }
1131    else {
1132       faf_id = FALSE;
1133       faf_ext = 0;
1134    }
1135 
1136    /* special setup for Plug and Play hardware */
1137    if (call_vbeaf_asm(af_driver->PlugAndPlayInit) != 0) {
1138       vbeaf_exit(NULL);
1139       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF Plug and Play initialisation failed"));
1140       return FALSE;
1141    }
1142 
1143    /* deal with all that DPMI memory mapping crap */
1144    ret = initialise_vbeaf_driver();
1145    if (ret != 0) {
1146       vbeaf_exit(NULL);
1147       if (ret == -2)
1148 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF nearptrs not supported on this platform"));
1149       else
1150 	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can't map memory for VBE/AF"));
1151       return FALSE;
1152    }
1153 
1154    /* low level driver initialisation */
1155    if (call_vbeaf_asm(af_driver->InitDriver) != 0) {
1156       vbeaf_exit(NULL);
1157       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VBE/AF device not present"));
1158       return FALSE;
1159    }
1160 
1161    return TRUE;
1162 }
1163 
1164 
1165 
1166 /* vbeaf_init:
1167  *  Tries to enter the specified graphics mode, and makes a screen bitmap
1168  *  for it.
1169  */
vbeaf_init(int w,int h,int v_w,int v_h,int color_depth)1170 static BITMAP *vbeaf_init(int w, int h, int v_w, int v_h, int color_depth)
1171 {
1172    BITMAP *b;
1173    AF_MODE_INFO mode_info;
1174    int bpp = BYTES_PER_PIXEL(color_depth);
1175    int bytes_per_scanline, width, height;
1176    int scrollable, mode;
1177    int vseg;
1178    int rs, gs, bs;
1179    char tmp1[512];
1180    void *vaddr;
1181 
1182    /* Do not continue if this version of Allegro was built in C-only mode.
1183     * The bank switchers assume asm-mode calling conventions, but the
1184     * library would try to call them with C calling conventions.
1185     */
1186 #ifdef ALLEGRO_NO_ASM
1187    return NULL;
1188 #endif
1189 
1190    /* locate and load VBE/AF driver from disk */
1191    if (!vbeaf_locate_driver())
1192       return NULL;
1193 
1194    LOCK_VARIABLE(af_driver);
1195    LOCK_VARIABLE(_accel_driver);
1196    LOCK_VARIABLE(_accel_active);
1197    LOCK_VARIABLE(_accel_set_bank);
1198    LOCK_VARIABLE(_accel_idle);
1199    LOCK_VARIABLE(vbeaf_cur_on);
1200    LOCK_VARIABLE(vbeaf_cur_x);
1201    LOCK_VARIABLE(vbeaf_cur_y);
1202    LOCK_FUNCTION(_accel_bank_switch);
1203    LOCK_FUNCTION(_accel_bank_stub);
1204    LOCK_FUNCTION(_af_wrapper);
1205    LOCK_FUNCTION(vbeaf_no_wait);
1206    LOCK_FUNCTION(vbeaf_move_mouse);
1207    LOCK_FUNCTION(vbeaf_draw_sprite);
1208    LOCK_FUNCTION(vbeaf_blit_from_memory);
1209 
1210    /* init the currently loaded VBE/AF driver */
1211    if (!vbeaf_lowlevel_init())
1212       return NULL;
1213 
1214    /* bodge to work around bugs in the present (6.51) version of UniVBE */
1215    if ((v_w > w) && (!faf_id)) {
1216       vbeaf_exit(NULL);
1217       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("SciTech VBE/AF drivers do not support wide virtual screens"));
1218       return NULL;
1219    }
1220 
1221    /* get ourselves a mode number */
1222    mode = find_vbeaf_mode(w, h, v_w, v_h, color_depth, &mode_info);
1223    if (mode == 0) {
1224       vbeaf_exit(NULL);
1225       return NULL;
1226    }
1227 
1228    gfx_vbeaf.vid_mem = af_driver->TotalMemory * 1024;
1229 
1230    vaddr = NULL;
1231 
1232    if (mode_info.Attributes & 8) {
1233       /* linear framebuffer */
1234       gfx_vbeaf.linear = TRUE;
1235       gfx_vbeaf.bank_size = gfx_vbeaf.bank_gran = 0;
1236       gfx_vbeaf.vid_phys_base = af_driver->LinearBasePtr;
1237       bytes_per_scanline = mode_info.LinBytesPerScanLine;
1238 
1239       if (faf_farptr) {
1240 	 vaddr = (void *)faf_farptr->LinearMem.offset;
1241 	 vseg = faf_farptr->LinearMem.sel;
1242       }
1243       else {
1244 	 vaddr = af_driver->LinearMem;
1245 	 vseg = _default_ds();
1246       }
1247    }
1248    else {
1249       /* banked framebuffer */
1250       gfx_vbeaf.linear = FALSE;
1251       gfx_vbeaf.bank_size = 65536;
1252       gfx_vbeaf.bank_gran = af_driver->BankSize * 1024;
1253       gfx_vbeaf.vid_phys_base = af_driver->BankedBasePtr;
1254       bytes_per_scanline = mode_info.BytesPerScanLine;
1255 
1256       if (faf_farptr) {
1257 	 vaddr = (void *)faf_farptr->BankedMem.offset;
1258 	 vseg = faf_farptr->BankedMem.sel;
1259       }
1260       else {
1261 	 vaddr = af_driver->BankedMem;
1262 	 vseg = _default_ds();
1263       }
1264    }
1265 
1266    width = MAX(bytes_per_scanline, v_w*bpp);
1267    height = MAX(h, v_h);
1268    _sort_out_virtual_width(&width, &gfx_vbeaf);
1269 
1270    if (width * height > gfx_vbeaf.vid_mem) {
1271       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Insufficient video memory"));
1272       vbeaf_exit(NULL);
1273       return NULL;
1274    }
1275 
1276    /* set the mode */
1277    if (set_vbeaf_mode(mode, w, h, width/bpp, height, &width, &scrollable) != 0) {
1278       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Failed to set VBE/AF mode"));
1279       vbeaf_exit(NULL);
1280       return NULL;
1281    }
1282 
1283    in_af_mode = TRUE;
1284    _accel_active = FALSE;
1285 
1286    if (scrollable)
1287       height = MAX(height, (int)af_driver->OffscreenEndY+1);
1288 
1289    if ((width/bpp < v_w) || (width/bpp < w) || (height < v_h) || (height < h)) {
1290       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Virtual screen size too large"));
1291       vbeaf_exit(NULL);
1292       return NULL;
1293    }
1294 
1295    /* construct the screen bitmap */
1296    b = _make_bitmap(width/bpp, height, (unsigned long)vaddr, &gfx_vbeaf, color_depth, width);
1297    if (!b) {
1298       vbeaf_exit(NULL);
1299       return NULL;
1300    }
1301 
1302    b->seg = vseg;
1303 
1304    /* set up the /AF driver state */
1305    af_driver->SetActiveBuffer(af_driver, 0);
1306    af_driver->SetVisibleBuffer(af_driver, 0, 0);
1307 
1308    if (af_driver->EnableDirectAccess)
1309       af_driver->EnableDirectAccess(af_driver);
1310 
1311    if (af_driver->SetClipRect)
1312       af_driver->SetClipRect(af_driver, 0, 0, b->w-1, b->h-1);
1313 
1314    _accel_set_bank = af_driver->SetBank;
1315 
1316    if (af_driver->EnableDirectAccess)
1317       _accel_idle = af_driver->EnableDirectAccess;
1318    else if (af_driver->WaitTillIdle)
1319       _accel_idle = af_driver->WaitTillIdle;
1320    else
1321       _accel_idle = vbeaf_no_wait;
1322 
1323    if (gfx_vbeaf.linear) {
1324       if (_accel_idle == vbeaf_no_wait)
1325 	 b->write_bank = b->read_bank = _stub_bank_switch;
1326       else
1327 	 b->write_bank = b->read_bank = _accel_bank_stub;
1328    }
1329    else {
1330       b->write_bank = b->read_bank = _accel_bank_switch;
1331       b->id |= BMP_ID_NOBLIT;
1332    }
1333 
1334    vbeaf_xscroll = vbeaf_yscroll = 0;
1335 
1336    gfx_vbeaf.w = b->cr = w;
1337    gfx_vbeaf.h = b->cb = h;
1338 
1339    /* set up the truecolor pixel format */
1340    #if (defined ALLEGRO_COLOR16) || (defined ALLEGRO_COLOR24) || (defined ALLEGRO_COLOR32)
1341 
1342       if (gfx_vbeaf.linear) {
1343 	 rs = mode_info.LinRedFieldPosition;
1344 	 gs = mode_info.LinGreenFieldPosition;
1345 	 bs = mode_info.LinBlueFieldPosition;
1346       }
1347       else {
1348 	 rs = mode_info.RedFieldPosition;
1349 	 gs = mode_info.GreenFieldPosition;
1350 	 bs = mode_info.BlueFieldPosition;
1351       }
1352 
1353       switch (color_depth) {
1354 
1355 	 #ifdef ALLEGRO_COLOR16
1356 
1357 	    case 15:
1358 	       _rgb_r_shift_15 = rs;
1359 	       _rgb_g_shift_15 = gs;
1360 	       _rgb_b_shift_15 = bs;
1361 	       break;
1362 
1363 	    case 16:
1364 	       _rgb_r_shift_16 = rs;
1365 	       _rgb_g_shift_16 = gs;
1366 	       _rgb_b_shift_16 = bs;
1367 	       break;
1368 
1369 	 #endif
1370 
1371 	 #ifdef ALLEGRO_COLOR24
1372 
1373 	    case 24:
1374 	       _rgb_r_shift_24 = rs;
1375 	       _rgb_g_shift_24 = gs;
1376 	       _rgb_b_shift_24 = bs;
1377 	       break;
1378 
1379 	 #endif
1380 
1381 	 #ifdef ALLEGRO_COLOR32
1382 
1383 	    case 32:
1384 	       _rgb_r_shift_32 = rs;
1385 	       _rgb_g_shift_32 = gs;
1386 	       _rgb_b_shift_32 = bs;
1387 	       break;
1388 
1389 	 #endif
1390       }
1391 
1392    #endif
1393 
1394    orig_vline = _screen_vtable.vline;
1395    orig_hline = _screen_vtable.hline;
1396    orig_line = _screen_vtable.line;
1397    orig_rectfill = _screen_vtable.rectfill;
1398    orig_draw_glyph = _screen_vtable.draw_glyph;
1399    orig_draw_sprite = _screen_vtable.draw_sprite;
1400    orig_masked_blit = _screen_vtable.masked_blit;
1401 
1402    /* is triple buffering supported? */
1403    if (mode_info.Attributes & 2048) {
1404       gfx_vbeaf.request_scroll = vbeaf_request_scroll;
1405       gfx_vbeaf.poll_scroll = vbeaf_poll_scroll;
1406    }
1407    else {
1408       gfx_vbeaf.request_scroll = NULL;
1409       gfx_vbeaf.poll_scroll = NULL;
1410    }
1411 
1412    /* are hardware cursors supported? */
1413    if ((mode_info.Attributes & 64) && (af_driver->SetCursor)) {
1414       gfx_vbeaf.set_mouse_sprite = vbeaf_set_mouse_sprite;
1415       gfx_vbeaf.show_mouse = vbeaf_show_mouse;
1416       gfx_vbeaf.hide_mouse = vbeaf_hide_mouse;
1417       gfx_vbeaf.move_mouse = vbeaf_move_mouse;
1418    }
1419    else {
1420       gfx_vbeaf.set_mouse_sprite = NULL;
1421       gfx_vbeaf.show_mouse = NULL;
1422       gfx_vbeaf.hide_mouse = NULL;
1423       gfx_vbeaf.move_mouse = NULL;
1424    }
1425 
1426    /* accelerated scanline fills? */
1427    if (af_driver->DrawScan)
1428       gfx_capabilities |= (GFX_HW_HLINE | GFX_HW_HLINE_XOR);
1429 
1430    if (af_driver->DrawPattScan)
1431       gfx_capabilities |= GFX_HW_HLINE_SOLID_PATTERN;
1432 
1433    if (af_driver->DrawColorPattScan)
1434       gfx_capabilities |= GFX_HW_HLINE_COPY_PATTERN;
1435 
1436    /* accelerated line drawing? */
1437    if (af_driver->DrawLine)
1438       gfx_capabilities |= (GFX_HW_LINE | GFX_HW_LINE_XOR);
1439 
1440    /* accelerated rectangle fills? */
1441    if (af_driver->DrawRect) {
1442       _screen_vtable.clear_to_color = vbeaf_clear_to_color;
1443       gfx_capabilities |= (GFX_HW_FILL | GFX_HW_FILL_XOR);
1444    }
1445 
1446    if (af_driver->DrawPattRect)
1447       gfx_capabilities |= GFX_HW_FILL_SOLID_PATTERN;
1448 
1449    if (af_driver->DrawColorPattRect)
1450       gfx_capabilities |= GFX_HW_FILL_COPY_PATTERN;
1451 
1452    /* accelerated triangle drawing? */
1453    if (af_driver->DrawTrap)
1454       gfx_capabilities |= (GFX_HW_TRIANGLE | GFX_HW_TRIANGLE_XOR);
1455 
1456    /* accelerated monochrome text output? */
1457    if (af_driver->PutMonoImage) {
1458       _screen_vtable.draw_glyph = vbeaf_draw_glyph;
1459       gfx_capabilities |= GFX_HW_GLYPH;
1460    }
1461 
1462    /* accelerated video memory blits? */
1463    if (af_driver->BitBlt) {
1464       _screen_vtable.blit_to_self = vbeaf_blit_to_self;
1465       _screen_vtable.blit_to_self_forward = vbeaf_blit_to_self;
1466       _screen_vtable.blit_to_self_backward = vbeaf_blit_to_self;
1467       gfx_capabilities |= GFX_HW_VRAM_BLIT;
1468    }
1469 
1470    /* accelerated blits from system memory? */
1471    if (af_driver->BitBltSys) {
1472       _screen_vtable.blit_from_memory = vbeaf_blit_from_memory;
1473       _screen_vtable.blit_from_system = vbeaf_blit_from_memory;
1474       gfx_capabilities |= GFX_HW_MEM_BLIT;
1475    }
1476 
1477    /* accelerated masked blits? */
1478    if ((af_driver->SrcTransBlt) || (af_driver->SrcTransBltSys)) {
1479       _screen_vtable.masked_blit = vbeaf_masked_blit;
1480       _screen_vtable.draw_sprite = vbeaf_draw_sprite;
1481 
1482       if (_screen_vtable.draw_256_sprite == orig_draw_sprite)
1483 	 _screen_vtable.draw_256_sprite = vbeaf_draw_sprite;
1484 
1485       if (af_driver->SrcTransBlt)
1486 	 gfx_capabilities |= GFX_HW_VRAM_BLIT_MASKED;
1487 
1488       if (af_driver->SrcTransBltSys)
1489 	 gfx_capabilities |= GFX_HW_MEM_BLIT_MASKED;
1490    }
1491 
1492    /* set up the VBE/AF description string */
1493    ustrzcpy(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(af_driver->OemVendorName, tmp1));
1494 
1495    if (gfx_vbeaf.linear)
1496       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", linear", tmp1));
1497    else
1498       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", banked", tmp1));
1499 
1500    if (faf_ext > 0)
1501       uszprintf(vbeaf_desc+ustrsize(vbeaf_desc), sizeof(vbeaf_desc) - ustrsize(vbeaf_desc),
1502 		uconvert_ascii(", FreeBE ex%02d", tmp1), faf_ext);
1503    else if (faf_id)
1504       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", FreeBE noex", tmp1));
1505 
1506    if (faf_farptr)
1507       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", farptr", tmp1));
1508 
1509    /* is this an accelerated or dumb framebuffer mode? */
1510    if (mode_info.Attributes & 16) {
1511       gfx_vbeaf.drawing_mode = vbeaf_drawing_mode;
1512       vbeaf_drawing_mode();
1513       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", accel", tmp1));
1514    }
1515    else {
1516       gfx_vbeaf.drawing_mode = NULL;
1517       ustrzcat(vbeaf_desc, sizeof(vbeaf_desc), uconvert_ascii(", noaccel", tmp1));
1518    }
1519 
1520    gfx_vbeaf.desc = vbeaf_desc;
1521 
1522    #ifdef ALLEGRO_LINUX
1523 
1524       __al_linux_console_graphics();
1525 
1526       b->vtable->acquire = __al_linux_acquire_bitmap;
1527       b->vtable->release = __al_linux_release_bitmap;
1528 
1529    #endif
1530 
1531    return b;
1532 }
1533 
1534 
1535 
1536 /* vbeaf_exit:
1537  *  Shuts down the VBE/AF driver.
1538  */
vbeaf_exit(BITMAP * b)1539 static void vbeaf_exit(BITMAP *b)
1540 {
1541    int c;
1542 
1543    /* shut down the driver */
1544    if (in_af_mode) {
1545       if (af_driver->EnableDirectAccess)
1546 	 af_driver->EnableDirectAccess(af_driver);
1547       else if (af_driver->WaitTillIdle)
1548 	 af_driver->WaitTillIdle(af_driver);
1549 
1550       af_driver->RestoreTextMode(af_driver);
1551       in_af_mode = FALSE;
1552    }
1553 
1554    /* undo memory mappings */
1555    if (faf_farptr) {
1556       for (c=0; c<4; c++)
1557 	 _remove_selector(&faf_farptr->IOMemMaps[c].sel);
1558 
1559       _remove_selector(&faf_farptr->BankedMem.sel);
1560       _remove_selector(&faf_farptr->LinearMem.sel);
1561    }
1562 
1563    for (c=0; c<4; c++)
1564       _remove_linear_mapping(af_memmap+c);
1565 
1566    _remove_linear_mapping(&af_banked_mem);
1567    _remove_linear_mapping(&af_linear_mem);
1568 
1569    if (af_driver) {
1570       _AL_FREE(af_driver);
1571       af_driver = _accel_driver = NULL;
1572    }
1573 
1574    #ifdef ALLEGRO_DOS
1575 
1576       if (vbeaf_nearptr) {
1577 	 __djgpp_nearptr_disable();
1578 	 vbeaf_nearptr = FALSE;
1579       }
1580 
1581    #endif
1582 
1583    #ifdef ALLEGRO_LINUX
1584 
1585       __al_linux_console_text();
1586 
1587    #endif
1588 }
1589 
1590 
1591 
1592 /* vbeaf_save:
1593  *  Saves the graphics state.
1594  */
vbeaf_save(void)1595 static void vbeaf_save(void)
1596 {
1597    if (af_driver->EnableDirectAccess)
1598       af_driver->EnableDirectAccess(af_driver);
1599    else if (af_driver->WaitTillIdle)
1600       af_driver->WaitTillIdle(af_driver);
1601 
1602    af_driver->RestoreTextMode(af_driver);
1603 
1604    in_af_mode = FALSE;
1605 }
1606 
1607 
1608 
1609 /* vbeaf_restore:
1610  *  Restores the graphics state.
1611  */
vbeaf_restore(void)1612 static void vbeaf_restore(void)
1613 {
1614    long wret = saved_wret;
1615 
1616    af_driver->SetVideoMode(af_driver, saved_mode, saved_vw, saved_vh, &wret, 1, NULL);
1617 
1618    af_driver->SetActiveBuffer(af_driver, 0);
1619    af_driver->SetVisibleBuffer(af_driver, 0, 0);
1620 
1621    if (af_driver->EnableDirectAccess)
1622       af_driver->EnableDirectAccess(af_driver);
1623 
1624    if (af_driver->SetClipRect)
1625       af_driver->SetClipRect(af_driver, 0, 0, SCREEN_W-1, SCREEN_H-1);
1626 
1627    if (gfx_vbeaf.drawing_mode)
1628       gfx_vbeaf.drawing_mode();
1629 
1630    vbeaf_scroll(vbeaf_xscroll, vbeaf_yscroll);
1631 
1632    in_af_mode = TRUE;
1633 }
1634 
1635 
1636 
1637 /* vbeaf_fetch_mode_list:
1638  *  Attempts to create a list of valid video modes for the VBE/AF driver.
1639  *  Returns the mode list on success or NULL on failure.
1640  */
vbeaf_fetch_mode_list(void)1641 static GFX_MODE_LIST *vbeaf_fetch_mode_list(void)
1642 {
1643    GFX_MODE_LIST *gfx_mode_list;
1644    AF_MODE_INFO *mode_info;
1645    unsigned short *mode;
1646    int vbeaf_was_off;
1647 
1648    mode_info = _AL_MALLOC(sizeof(AF_MODE_INFO));
1649    if (!mode_info) return NULL;
1650 
1651    /* make sure VBE/AF interface is enabled! */
1652    if (!af_driver) {
1653       if (!vbeaf_locate_driver()) {
1654          if (mode_info) _AL_FREE(mode_info);
1655 
1656          return NULL;
1657       }
1658       if (!vbeaf_lowlevel_init()) {
1659          if (mode_info) _AL_FREE(mode_info);
1660 
1661          return NULL;
1662       }
1663       vbeaf_was_off = TRUE;
1664    }
1665    else
1666       vbeaf_was_off = FALSE;
1667 
1668    /* start building mode-list */
1669    gfx_mode_list = _AL_MALLOC(sizeof(GFX_MODE_LIST));
1670    if (!gfx_mode_list) {
1671       if (mode_info) _AL_FREE(mode_info);
1672 
1673       return NULL;
1674    }
1675    gfx_mode_list->mode = NULL;
1676    gfx_mode_list->num_modes = 0;
1677 
1678    /* create mode list */
1679    for (mode = af_driver->AvailableModes; *mode != 0xFFFF; mode++) {
1680       gfx_mode_list->mode = _al_sane_realloc(gfx_mode_list->mode, sizeof(GFX_MODE) * (gfx_mode_list->num_modes + 1));
1681       if (!gfx_mode_list->mode) {
1682          if (mode_info) _AL_FREE(mode_info);
1683          if (gfx_mode_list) _AL_FREE(gfx_mode_list);
1684 
1685          return NULL;
1686       }
1687       if (af_driver->GetVideoModeInfo(af_driver, *mode, mode_info) != 0) {
1688          if (mode_info) _AL_FREE(mode_info);
1689          if (gfx_mode_list->mode) _AL_FREE(gfx_mode_list->mode);
1690          if (gfx_mode_list) _AL_FREE(gfx_mode_list);
1691 
1692          return NULL;
1693       }
1694 
1695       gfx_mode_list->mode[gfx_mode_list->num_modes].width  = mode_info->XResolution;
1696       gfx_mode_list->mode[gfx_mode_list->num_modes].height = mode_info->YResolution;
1697       gfx_mode_list->mode[gfx_mode_list->num_modes].bpp    = mode_info->BitsPerPixel;
1698 
1699       gfx_mode_list->num_modes++;
1700    }
1701 
1702    /* terminate mode list */
1703    gfx_mode_list->mode = _al_sane_realloc(gfx_mode_list->mode, sizeof(GFX_MODE) * (gfx_mode_list->num_modes + 1));
1704    if (!gfx_mode_list->mode) {
1705       if (mode_info) _AL_FREE(mode_info);
1706       if (gfx_mode_list) _AL_FREE(gfx_mode_list);
1707 
1708       return NULL;
1709    }
1710 
1711    gfx_mode_list->mode[gfx_mode_list->num_modes].width  = 0;
1712    gfx_mode_list->mode[gfx_mode_list->num_modes].height = 0;
1713    gfx_mode_list->mode[gfx_mode_list->num_modes].bpp    = 0;
1714 
1715    /* shut down VBE/AF interface if it wasn't previously loaded */
1716    if (vbeaf_was_off)
1717       vbeaf_exit(NULL);
1718 
1719    if (mode_info) _AL_FREE(mode_info);
1720 
1721    return gfx_mode_list;
1722 }
1723 
1724 
1725 
1726 /* vbeaf_vsync:
1727  *  VBE/AF vsync routine, needed for cards that don't emulate the VGA
1728  *  blanking registers. VBE/AF doesn't provide a vsync function, but we
1729  *  can emulate it by altering the display start address with the vsync
1730  *  flag set.
1731  */
vbeaf_vsync(void)1732 static void vbeaf_vsync(void)
1733 {
1734    vbeaf_scroll(vbeaf_xscroll, vbeaf_yscroll);
1735 }
1736 
1737 
1738 
1739 /* vbeaf_scroll:
1740  *  Hardware scrolling routine.
1741  */
vbeaf_scroll(int x,int y)1742 static int vbeaf_scroll(int x, int y)
1743 {
1744    int moved = (vbeaf_xscroll != x) || (vbeaf_yscroll != y);
1745 
1746    vbeaf_xscroll = x;
1747    vbeaf_yscroll = y;
1748 
1749    SAFISH_CALL(
1750       if (_wait_for_vsync && af_driver->WaitTillIdle)
1751 	 af_driver->WaitTillIdle(af_driver);
1752 
1753       af_driver->SetDisplayStart(af_driver, x, y, 1);
1754    );
1755 
1756    if ((vbeaf_cur_bmp) && (moved))
1757       vbeaf_move_mouse(vbeaf_cur_x, vbeaf_cur_y);
1758 
1759    return 0;
1760 }
1761 
1762 
1763 
1764 /* vbeaf_set_palette_range:
1765  *  Uses VBE/AF functions to set the palette.
1766  */
vbeaf_set_palette_range(AL_CONST PALETTE p,int from,int to,int vsync)1767 static void vbeaf_set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync)
1768 {
1769    AF_PALETTE tmp[256];
1770    int c;
1771 
1772    for (c=from; c<=to; c++) {
1773       tmp[c-from].red = p[c].r << 2;
1774       tmp[c-from].green = p[c].g << 2;
1775       tmp[c-from].blue = p[c].b << 2;
1776       tmp[c-from].alpha = 0;
1777    }
1778 
1779    SAFISH_CALL(
1780       af_driver->SetPaletteData(af_driver, tmp, to-from+1, from, (vsync ? 1 : 0));
1781    );
1782 }
1783 
1784 
1785 
1786 /* vbeaf_request_scroll:
1787  *  Triple buffering initiate routine.
1788  */
vbeaf_request_scroll(int x,int y)1789 static int vbeaf_request_scroll(int x, int y)
1790 {
1791    vbeaf_xscroll = x;
1792    vbeaf_yscroll = y;
1793 
1794    SAFISH_CALL(
1795       if (af_driver->WaitTillIdle)
1796 	 af_driver->WaitTillIdle(af_driver);
1797 
1798       af_driver->SetDisplayStart(af_driver, x, y, 0);
1799    );
1800 
1801    if (vbeaf_cur_bmp)
1802       vbeaf_move_mouse(vbeaf_cur_x, vbeaf_cur_y);
1803 
1804    return 0;
1805 }
1806 
1807 
1808 
1809 /* vbeaf_poll_scroll:
1810  *  Triple buffering test routine.
1811  */
vbeaf_poll_scroll(void)1812 static int vbeaf_poll_scroll(void)
1813 {
1814    int ret;
1815 
1816    SAFISH_CALL(
1817       ret = af_driver->GetDisplayStartStatus(af_driver);
1818    );
1819 
1820    return (ret) ? FALSE : TRUE;
1821 }
1822 
1823 
1824 
1825 /* vbeaf_set_mouse_sprite:
1826  *  Attempts to download a new hardware cursor graphic, returning zero on
1827  *  success or non-zero if this image is unsuitable.
1828  */
vbeaf_set_mouse_sprite(BITMAP * sprite,int xfocus,int yfocus)1829 static int vbeaf_set_mouse_sprite(BITMAP *sprite, int xfocus, int yfocus)
1830 {
1831    AF_CURSOR cursor;
1832    int bpp = bitmap_color_depth(sprite);
1833    int c, x, y;
1834    int iszero;
1835 
1836    /* hardware cursors cannot be larger than 32x32 */
1837    if ((sprite->w > 32) || (sprite->h > 32))
1838       return -1;
1839 
1840    /* clear the cursor data */
1841    for (c=0; c<32; c++) {
1842       cursor.andMask[c] = 0;
1843       cursor.xorMask[c] = 0;
1844    }
1845 
1846    vbeaf_cur_c1 = -1;
1847    vbeaf_cur_c2 = -1;
1848 
1849    /* scan through the pointer image */
1850    for (y=0; y<sprite->h; y++) {
1851       for (x=0; x<sprite->w; x++) {
1852 
1853 	 c = getpixel(sprite, x, y);
1854 
1855 	 if (c == bitmap_mask_color(sprite)) {
1856 	    /* skip masked pixels */
1857 	 }
1858 	 else if (c == vbeaf_cur_c1) {
1859 	    /* color #1 pixel */
1860 	    cursor.andMask[y] |= 0x80000000>>x;
1861 	    cursor.xorMask[y] |= 0x80000000>>x;
1862 	 }
1863 	 else if (c == vbeaf_cur_c2) {
1864 	    /* color #2 pixel */
1865 	    cursor.andMask[y] |= 0x80000000>>x;
1866 	 }
1867 	 else {
1868 	    /* check whether this pixel value is zero */
1869 	    if (bpp == 8) {
1870 	       iszero = ((getr_depth(bpp, c) == getr_depth(bpp, 0)) &&
1871 			 (getg_depth(bpp, c) == getg_depth(bpp, 0)) &&
1872 			 (getb_depth(bpp, c) == getb_depth(bpp, 0)));
1873 	    }
1874 	    else {
1875 	       iszero = ((getr_depth(bpp, c) == 0) &&
1876 			 (getg_depth(bpp, c) == 0) &&
1877 			 (getb_depth(bpp, c) == 0));
1878 	    }
1879 
1880 	    if ((vbeaf_cur_c2 < 0) && (iszero)) {
1881 	       /* zero pixel value = color #2 */
1882 	       vbeaf_cur_c2 = c;
1883 	       cursor.andMask[y] |= 0x80000000>>x;
1884 	    }
1885 	    else if (vbeaf_cur_c1 < 0) {
1886 	       /* other pixel value = color #1 */
1887 	       vbeaf_cur_c1 = c;
1888 	       cursor.andMask[y] |= 0x80000000>>x;
1889 	       cursor.xorMask[y] |= 0x80000000>>x;
1890 	    }
1891 	    else {
1892 	       /* it's not cool if there are more than two colors! */
1893 	       return -1;
1894 	    }
1895 	 }
1896       }
1897    }
1898 
1899    /* flip the endianess */
1900    for (c=0; c<32; c++) {
1901       cursor.andMask[c] = bswap(cursor.andMask[c]);
1902       cursor.xorMask[c] = bswap(cursor.xorMask[c]);
1903    }
1904 
1905    cursor.hotx = xfocus;
1906    cursor.hoty = yfocus;
1907 
1908    /* download to the hardware */
1909    SAFISH_CALL(
1910       af_driver->SetCursor(af_driver, &cursor);
1911 
1912       if ((bpp > 8) && (vbeaf_cur_c1 >= 0)) {
1913 	 af_driver->SetCursorColor(af_driver,
1914 				   getr_depth(bpp, vbeaf_cur_c1),
1915 				   getg_depth(bpp, vbeaf_cur_c1),
1916 				   getb_depth(bpp, vbeaf_cur_c1));
1917       }
1918    );
1919 
1920    return 0;
1921 }
1922 
1923 
1924 
1925 /* vbeaf_show_mouse:
1926  *  Turns on the hardware cursor, returning zero on success.
1927  */
vbeaf_show_mouse(BITMAP * bmp,int x,int y)1928 static int vbeaf_show_mouse(BITMAP *bmp, int x, int y)
1929 {
1930    if (bitmap_color_depth(bmp) == 8) {
1931       if (vbeaf_cur_c2 >= 0) {
1932 	 /* check that the palette contains a valid zero color */
1933 	 if ((getr_depth(8, vbeaf_cur_c2) != getr_depth(8, 0)) ||
1934 	     (getg_depth(8, vbeaf_cur_c2) != getg_depth(8, 0)) ||
1935 	     (getb_depth(8, vbeaf_cur_c2) != getb_depth(8, 0)))
1936 	    return -1;
1937       }
1938 
1939       /* set the cursor color */
1940       if (vbeaf_cur_c1 >= 0) {
1941 	 SAFISH_CALL(
1942 	    af_driver->SetCursorColor(af_driver, vbeaf_cur_c1, 0, 0);
1943 	 );
1944       }
1945    }
1946 
1947    vbeaf_cur_bmp = bmp;
1948    vbeaf_cur_on = FALSE;
1949 
1950    vbeaf_move_mouse(x, y);
1951 
1952    return 0;
1953 }
1954 
1955 
1956 
1957 /* vbeaf_hide_mouse:
1958  *  Gets rid of the hardware cursor.
1959  */
vbeaf_hide_mouse(void)1960 static void vbeaf_hide_mouse(void)
1961 {
1962    SAFISH_CALL(
1963       af_driver->ShowCursor(af_driver, 0);
1964    );
1965 
1966    vbeaf_cur_bmp = NULL;
1967    vbeaf_cur_on = FALSE;
1968 }
1969 
1970 
1971 
1972 /* vbeaf_move_mouse:
1973  *  Sets the hardware cursor position.
1974  */
vbeaf_move_mouse(int x,int y)1975 static void vbeaf_move_mouse(int x, int y)
1976 {
1977    int hx, hy;
1978    int onscreen;
1979 
1980    hx = x + vbeaf_cur_bmp->x_ofs - vbeaf_xscroll;
1981    hy = y + vbeaf_cur_bmp->y_ofs - vbeaf_yscroll;
1982 
1983    onscreen = (hx >= 0) && (hx < SCREEN_W) && (hy >= 0) && (hy < SCREEN_H);
1984 
1985    SAFISH_CALL(
1986       if (onscreen) {
1987 	 af_driver->SetCursorPos(af_driver, hx, hy);
1988 
1989 	 if (!vbeaf_cur_on) {
1990 	    af_driver->ShowCursor(af_driver, 1);
1991 	    vbeaf_cur_on = TRUE;
1992 	 }
1993       }
1994       else {
1995 	 if (vbeaf_cur_on) {
1996 	    af_driver->ShowCursor(af_driver, 0);
1997 	    vbeaf_cur_on = FALSE;
1998 	 }
1999       }
2000    );
2001 
2002    vbeaf_cur_x = x;
2003    vbeaf_cur_y = y;
2004 }
2005 
2006 END_OF_STATIC_FUNCTION(vbeaf_move_mouse);
2007 
2008 
2009 
2010 /* vbeaf_drawing_mode:
2011  *  Hook to tell us that the drawing mode has been changed, so we may need
2012  *  to alter some of our vtable entries.
2013  */
vbeaf_drawing_mode(void)2014 static void vbeaf_drawing_mode(void)
2015 {
2016    vbeaf_pattern = NULL;
2017 
2018    if ((_drawing_mode == DRAW_MODE_SOLID) || (_drawing_mode == DRAW_MODE_XOR)) {
2019       /* easy, everything supports solid and XOR drawing */
2020       _screen_vtable.hline = (af_driver->DrawScan) ? vbeaf_hline : orig_hline;
2021       _screen_vtable.vline = (af_driver->DrawLine) ? vbeaf_vline_a : ((af_driver->DrawRect) ? vbeaf_vline_b : orig_vline);
2022       _screen_vtable.line = (af_driver->DrawLine) ? vbeaf_line : orig_line;
2023       _screen_vtable.rectfill = (af_driver->DrawRect) ? vbeaf_rectfill : orig_rectfill;
2024       _screen_vtable.triangle = (af_driver->DrawTrap) ? vbeaf_triangle : NULL;
2025 
2026       vbeaf_fg_mix = vbeaf_bg_mix = (_drawing_mode == DRAW_MODE_XOR) ? 3 : 0;
2027 
2028       SAFISH_CALL(
2029 	 af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2030       );
2031       return;
2032    }
2033 
2034    if ((_drawing_mode == DRAW_MODE_COPY_PATTERN) &&
2035        (_drawing_pattern->w <= 8) && (_drawing_pattern->h <= 8)) {
2036       /* color patterns can be done in hardware if they are small enough */
2037       _screen_vtable.hline = (af_driver->DrawColorPattScan) ? vbeaf_hline : orig_hline;
2038       _screen_vtable.vline = (af_driver->DrawColorPattRect) ? vbeaf_vline_b : orig_vline;
2039       _screen_vtable.line = orig_line;
2040       _screen_vtable.rectfill = (af_driver->DrawColorPattRect) ? vbeaf_rectfill : orig_rectfill;
2041       _screen_vtable.triangle = NULL;
2042 
2043       vbeaf_fg_mix = vbeaf_bg_mix = 0;
2044 
2045       SAFISH_CALL(
2046 	 af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2047       );
2048       return;
2049    }
2050 
2051    if (((_drawing_mode == DRAW_MODE_SOLID_PATTERN) || (_drawing_mode == DRAW_MODE_MASKED_PATTERN)) &&
2052        (_drawing_pattern->w <= 8) && (_drawing_pattern->h <= 8)) {
2053       /* mono patterns can be done in hardware if they are small enough */
2054       _screen_vtable.hline = (af_driver->DrawPattScan) ? vbeaf_hline : orig_hline;
2055       _screen_vtable.vline = (af_driver->DrawPattRect) ? vbeaf_vline_b : orig_vline;
2056       _screen_vtable.line = orig_line;
2057       _screen_vtable.rectfill = (af_driver->DrawPattRect) ? vbeaf_rectfill : orig_rectfill;
2058       _screen_vtable.triangle = NULL;
2059 
2060       vbeaf_fg_mix = 0;
2061       vbeaf_bg_mix = (_drawing_mode == DRAW_MODE_MASKED_PATTERN) ? 4 : 0;
2062 
2063       SAFISH_CALL(
2064 	 af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2065       );
2066       return;
2067    }
2068 
2069    /* urgh, have to use software drawing functions for this mode */
2070    _screen_vtable.vline = orig_vline;
2071    _screen_vtable.hline = orig_hline;
2072    _screen_vtable.line = orig_line;
2073    _screen_vtable.rectfill = orig_rectfill;
2074    _screen_vtable.triangle = NULL;
2075 
2076    vbeaf_fg_mix = vbeaf_bg_mix = 0;
2077 
2078    SAFISH_CALL(
2079       af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2080    );
2081 }
2082 
2083 
2084 
2085 /* prepare_color_pattern:
2086  *  Sets up the hardware ready for a colored pattern drawing operation.
2087  */
prepare_color_pattern(BITMAP * bmp)2088 static void prepare_color_pattern(BITMAP *bmp)
2089 {
2090    static unsigned long pattern[64];
2091    int x, y, xx, yy, xo, yo;
2092 
2093    if (vbeaf_pattern != bmp) {
2094       xo = _drawing_x_anchor + bmp->x_ofs;
2095       yo = _drawing_y_anchor + bmp->y_ofs;
2096 
2097       switch (bitmap_color_depth(bmp)) {
2098 
2099 	 #ifdef ALLEGRO_COLOR8
2100 
2101 	    case 8:
2102 	       for (y=0; y<8; y++) {
2103 		  for (x=0; x<8; x++) {
2104 		     xx = (x-xo) & _drawing_x_mask;
2105 		     yy = (y-yo) & _drawing_y_mask;
2106 		     pattern[y*8+x] = _drawing_pattern->line[yy][xx];
2107 		  }
2108 	       }
2109 	       break;
2110 
2111 	 #endif
2112 
2113 	 #ifdef ALLEGRO_COLOR16
2114 
2115 	    case 15:
2116 	    case 16:
2117 	       for (y=0; y<8; y++) {
2118 		  for (x=0; x<8; x++) {
2119 		     xx = (x-xo) & _drawing_x_mask;
2120 		     yy = (y-yo) & _drawing_y_mask;
2121 		     pattern[y*8+x] = ((unsigned short *)_drawing_pattern->line[yy])[xx];
2122 		  }
2123 	       }
2124 	       break;
2125 
2126 	 #endif
2127 
2128 	 #ifdef ALLEGRO_COLOR24
2129 
2130 	    case 24:
2131 	       for (y=0; y<8; y++) {
2132 		  for (x=0; x<8; x++) {
2133 		     xx = (x-xo) & _drawing_x_mask;
2134 		     yy = (y-yo) & _drawing_y_mask;
2135 		     pattern[y*8+x] = *((unsigned long *)(_drawing_pattern->line[yy]+xx*3)) & 0xFFFFFF;
2136 		  }
2137 	       }
2138 	       break;
2139 
2140 	 #endif
2141 
2142 	 #ifdef ALLEGRO_COLOR32
2143 
2144 	    case 32:
2145 	       for (y=0; y<8; y++) {
2146 		  for (x=0; x<8; x++) {
2147 		     xx = (x-xo) & _drawing_x_mask;
2148 		     yy = (y-yo) & _drawing_y_mask;
2149 		     pattern[y*8+x] = ((unsigned long *)_drawing_pattern->line[yy])[xx];
2150 		  }
2151 	       }
2152 	       break;
2153 
2154 	 #endif
2155       }
2156 
2157       af_driver->Set8x8ColorPattern(af_driver, 0, pattern);
2158       af_driver->Use8x8ColorPattern(af_driver, 0);
2159 
2160       vbeaf_pattern = bmp;
2161    }
2162 }
2163 
2164 
2165 
2166 /* prepare_mono_pattern:
2167  *  Sets up the hardware ready for a mono pattern drawing operation.
2168  */
prepare_mono_pattern(BITMAP * bmp)2169 static void prepare_mono_pattern(BITMAP *bmp)
2170 {
2171    static unsigned char pattern[8];
2172    int x, y, xx, yy, xo, yo;
2173 
2174    if (vbeaf_pattern != bmp) {
2175       xo = _drawing_x_anchor + bmp->x_ofs;
2176       yo = _drawing_y_anchor + bmp->y_ofs;
2177 
2178       switch (bitmap_color_depth(bmp)) {
2179 
2180 	 #ifdef ALLEGRO_COLOR16
2181 
2182 	    case 8:
2183 	       for (y=0; y<8; y++) {
2184 		  pattern[y] = 0;
2185 		  for (x=0; x<8; x++) {
2186 		     xx = (x-xo) & _drawing_x_mask;
2187 		     yy = (y-yo) & _drawing_y_mask;
2188 		     if (_drawing_pattern->line[yy][xx])
2189 			pattern[y] |= (0x80>>x);
2190 		  }
2191 	       }
2192 	       break;
2193 
2194 	 #endif
2195 
2196 	 #ifdef ALLEGRO_COLOR16
2197 
2198 	    case 15:
2199 	    case 16:
2200 	       for (y=0; y<8; y++) {
2201 		  pattern[y] = 0;
2202 		  for (x=0; x<8; x++) {
2203 		     xx = (x-xo) & _drawing_x_mask;
2204 		     yy = (y-yo) & _drawing_y_mask;
2205 		     if (((unsigned short *)_drawing_pattern->line[yy])[xx] != bitmap_mask_color(bmp))
2206 			pattern[y] |= (0x80>>x);
2207 		  }
2208 	       }
2209 	       break;
2210 
2211 	 #endif
2212 
2213 	 #ifdef ALLEGRO_COLOR24
2214 
2215 	    case 24:
2216 	       for (y=0; y<8; y++) {
2217 		  pattern[y] = 0;
2218 		  for (x=0; x<8; x++) {
2219 		     xx = (x-xo) & _drawing_x_mask;
2220 		     yy = (y-yo) & _drawing_y_mask;
2221 		     if ((*((unsigned long *)(_drawing_pattern->line[yy]+xx*3)) & 0xFFFFFF) != MASK_COLOR_24)
2222 			pattern[y] |= (0x80>>x);
2223 		  }
2224 	       }
2225 	       break;
2226 
2227 	 #endif
2228 
2229 	 #ifdef ALLEGRO_COLOR32
2230 
2231 	    case 32:
2232 	       for (y=0; y<8; y++) {
2233 		  pattern[y] = 0;
2234 		  for (x=0; x<8; x++) {
2235 		     xx = (x-xo) & _drawing_x_mask;
2236 		     yy = (y-yo) & _drawing_y_mask;
2237 		     if (((unsigned long *)_drawing_pattern->line[yy])[xx] != MASK_COLOR_32)
2238 			pattern[y] |= (0x80>>x);
2239 		  }
2240 	       }
2241 	       break;
2242 
2243 	 #endif
2244       }
2245 
2246       af_driver->Set8x8MonoPattern(af_driver, pattern);
2247 
2248       vbeaf_pattern = bmp;
2249    }
2250 }
2251 
2252 
2253 
2254 /* go_accel:
2255  *  Prepares the hardware for an accelerated drawing operation.
2256  */
go_accel(void)2257 static INLINE void go_accel(void)
2258 {
2259    /* turn on the accelerator */
2260    if (!_accel_active) {
2261       if (af_driver->DisableDirectAccess)
2262 	 af_driver->DisableDirectAccess(af_driver);
2263 
2264       _accel_active = TRUE;
2265    }
2266 }
2267 
2268 
2269 
2270 /* vbeaf_hline:
2271  *  Accelerated scanline filling routine.
2272  */
vbeaf_hline(BITMAP * bmp,int x1,int y,int x2,int color)2273 static void vbeaf_hline(BITMAP *bmp, int x1, int y, int x2, int color)
2274 {
2275    if (x1 > x2) {
2276       int tmp = x1;
2277       x1 = x2;
2278       x2 = tmp;
2279    }
2280 
2281    if (bmp->clip) {
2282       if ((y < bmp->ct) || (y >= bmp->cb))
2283 	 return;
2284 
2285       if (x1 < bmp->cl)
2286 	 x1 = bmp->cl;
2287 
2288       if (x2 >= bmp->cr)
2289 	 x2 = bmp->cr-1;
2290 
2291       if (x2 < x1)
2292 	 return;
2293    }
2294 
2295    SAFISH_CALL(
2296       go_accel();
2297 
2298       switch (_drawing_mode) {
2299 
2300 	 case DRAW_MODE_SOLID:
2301 	 case DRAW_MODE_XOR:
2302 	    /* normal scanline fill */
2303 	    af_driver->DrawScan(af_driver, color, y+bmp->y_ofs,
2304 				x1+bmp->x_ofs, x2+bmp->x_ofs+1);
2305 	    break;
2306 
2307 	 case DRAW_MODE_COPY_PATTERN:
2308 	    /* colored pattern scanline fill */
2309 	    prepare_color_pattern(bmp);
2310 
2311 	    af_driver->DrawColorPattScan(af_driver, y+bmp->y_ofs,
2312 					 x1+bmp->x_ofs, x2+bmp->x_ofs+1);
2313 	    break;
2314 
2315 	 case DRAW_MODE_SOLID_PATTERN:
2316 	 case DRAW_MODE_MASKED_PATTERN:
2317 	    /* mono pattern scanline fill */
2318 	    prepare_mono_pattern(bmp);
2319 
2320 	    af_driver->DrawPattScan(af_driver, color, 0, y+bmp->y_ofs,
2321 				    x1+bmp->x_ofs, x2+bmp->x_ofs+1);
2322 	    break;
2323       }
2324    );
2325 }
2326 
2327 
2328 
2329 /* vbeaf_vline_a:
2330  *  Accelerated vertical line drawer, using the VBE/AF line primitive.
2331  */
vbeaf_vline_a(BITMAP * bmp,int x,int y1,int y2,int color)2332 static void vbeaf_vline_a(BITMAP *bmp, int x, int y1, int y2, int color)
2333 {
2334    if (y1 > y2) {
2335       int tmp = y1;
2336       y1 = y2;
2337       y2 = tmp;
2338    }
2339 
2340    if (bmp->clip) {
2341       if ((x < bmp->cl) || (x >= bmp->cr))
2342 	 return;
2343 
2344       if (y1 < bmp->ct)
2345 	 y1 = bmp->ct;
2346 
2347       if (y2 >= bmp->cb)
2348 	 y2 = bmp->cb-1;
2349 
2350       if (y2 < y1)
2351 	 return;
2352    }
2353 
2354    SAFISH_CALL(
2355       go_accel();
2356 
2357       af_driver->DrawLine(af_driver, color,
2358 			  itofix(x+bmp->x_ofs), itofix(y1+bmp->y_ofs),
2359 			  itofix(x+bmp->x_ofs), itofix(y2+bmp->y_ofs));
2360    );
2361 }
2362 
2363 
2364 
2365 /* vbeaf_vline_b:
2366  *  Accelerated vertical line drawer, using the VBE/AF rectangle primitive.
2367  */
vbeaf_vline_b(BITMAP * bmp,int x,int y1,int y2,int color)2368 static void vbeaf_vline_b(BITMAP *bmp, int x, int y1, int y2, int color)
2369 {
2370    if (y1 > y2) {
2371       int tmp = y1;
2372       y1 = y2;
2373       y2 = tmp;
2374    }
2375 
2376    if (bmp->clip) {
2377       if ((x < bmp->cl) || (x >= bmp->cr))
2378 	 return;
2379 
2380       if (y1 < bmp->ct)
2381 	 y1 = bmp->ct;
2382 
2383       if (y2 >= bmp->cb)
2384 	 y2 = bmp->cb-1;
2385 
2386       if (y2 < y1)
2387 	 return;
2388    }
2389 
2390    SAFISH_CALL(
2391       go_accel();
2392 
2393       switch (_drawing_mode) {
2394 
2395 	 case DRAW_MODE_SOLID:
2396 	 case DRAW_MODE_XOR:
2397 	    /* mono vertical line */
2398 	    af_driver->DrawRect(af_driver, color,
2399 				x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1);
2400 	    break;
2401 
2402 	 case DRAW_MODE_COPY_PATTERN:
2403 	    /* colored pattern vertical line */
2404 	    prepare_color_pattern(bmp);
2405 
2406 	    af_driver->DrawColorPattRect(af_driver,
2407 					 x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1);
2408 	    break;
2409 
2410 	 case DRAW_MODE_SOLID_PATTERN:
2411 	 case DRAW_MODE_MASKED_PATTERN:
2412 	    /* mono pattern vertical line */
2413 	    prepare_mono_pattern(bmp);
2414 
2415 	    af_driver->DrawPattRect(af_driver, color, 0,
2416 				    x+bmp->x_ofs, y1+bmp->y_ofs, 1, y2-y1+1);
2417 	    break;
2418       }
2419    );
2420 }
2421 
2422 
2423 
2424 /* vbeaf_line:
2425  *  Accelerated line drawer.
2426  */
vbeaf_line(BITMAP * bmp,int x1,int y1,int x2,int y2,int color)2427 static void vbeaf_line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color)
2428 {
2429    int sx, sy, dx, dy, t;
2430 
2431    if (bmp->clip) {
2432       sx = x1;
2433       sy = y1;
2434       dx = x2;
2435       dy = y2;
2436 
2437       if (sx > dx) {
2438 	 t = sx;
2439 	 sx = dx;
2440 	 dx = t;
2441       }
2442 
2443       if (sy > dy) {
2444 	 t = sy;
2445 	 sy = dy;
2446 	 dy = t;
2447       }
2448 
2449       if ((sx >= bmp->cr) || (sy >= bmp->cb) || (dx < bmp->cl) || (dy < bmp->ct))
2450 	 return;
2451 
2452       if ((sx < bmp->cl) || (sy < bmp->ct) || (dx >= bmp->cr) || (dy >= bmp->cb)) {
2453 	 orig_line(bmp, x1, y1, x2, y2, color);
2454 	 return;
2455       }
2456    }
2457 
2458    SAFISH_CALL(
2459       go_accel();
2460 
2461       af_driver->DrawLine(af_driver, color,
2462 			  itofix(x1+bmp->x_ofs), itofix(y1+bmp->y_ofs),
2463 			  itofix(x2+bmp->x_ofs), itofix(y2+bmp->y_ofs));
2464    );
2465 }
2466 
2467 
2468 
2469 /* vbeaf_rectfill:
2470  *  Accelerated rectangle filling routine.
2471  */
vbeaf_rectfill(BITMAP * bmp,int x1,int y1,int x2,int y2,int color)2472 static void vbeaf_rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int color)
2473 {
2474    if (x2 < x1) {
2475       int tmp = x1;
2476       x1 = x2;
2477       x2 = tmp;
2478    }
2479 
2480    if (y2 < y1) {
2481       int tmp = y1;
2482       y1 = y2;
2483       y2 = tmp;
2484    }
2485 
2486    if (bmp->clip) {
2487       if (x1 < bmp->cl)
2488 	 x1 = bmp->cl;
2489 
2490       if (x2 >= bmp->cr)
2491 	 x2 = bmp->cr-1;
2492 
2493       if (x2 < x1)
2494 	 return;
2495 
2496       if (y1 < bmp->ct)
2497 	 y1 = bmp->ct;
2498 
2499       if (y2 >= bmp->cb)
2500 	 y2 = bmp->cb-1;
2501 
2502       if (y2 < y1)
2503 	 return;
2504    }
2505 
2506    SAFISH_CALL(
2507       go_accel();
2508 
2509       switch (_drawing_mode) {
2510 
2511 	 case DRAW_MODE_SOLID:
2512 	 case DRAW_MODE_XOR:
2513 	    /* mono rectangle fill */
2514 	    af_driver->DrawRect(af_driver, color,
2515 				x1+bmp->x_ofs, y1+bmp->y_ofs,
2516 				x2-x1+1, y2-y1+1);
2517 	    break;
2518 
2519 	 case DRAW_MODE_COPY_PATTERN:
2520 	    /* colored pattern rectangle fill */
2521 	    prepare_color_pattern(bmp);
2522 
2523 	    af_driver->DrawColorPattRect(af_driver,
2524 					 x1+bmp->x_ofs, y1+bmp->y_ofs,
2525 					 x2-x1+1, y2-y1+1);
2526 	    break;
2527 
2528 	 case DRAW_MODE_SOLID_PATTERN:
2529 	 case DRAW_MODE_MASKED_PATTERN:
2530 	    /* mono pattern rectangle fill */
2531 	    prepare_mono_pattern(bmp);
2532 
2533 	    af_driver->DrawPattRect(af_driver, color, 0,
2534 				    x1+bmp->x_ofs, y1+bmp->y_ofs,
2535 				    x2-x1+1, y2-y1+1);
2536 	    break;
2537       }
2538    );
2539 }
2540 
2541 
2542 
2543 /* vbeaf_triangle:
2544  *  Hardware accelerated triangle drawing function.
2545  */
vbeaf_triangle(BITMAP * bmp,int x1,int y1,int x2,int y2,int x3,int y3,int color)2546 static void vbeaf_triangle(BITMAP *bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color)
2547 {
2548    AF_TRAP trap;
2549 
2550    /* bounding box test */
2551    if (bmp->clip) {
2552       if ((x1 < bmp->cl) || (x2 < bmp->cl) || (x3 < bmp->cl)) {
2553          _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color);
2554 	 return;
2555       }
2556 
2557       if ((y1 < bmp->ct) || (y2 < bmp->ct) || (y3 < bmp->ct)) {
2558          _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color);
2559 	 return;
2560       }
2561 
2562       if ((x1 >= bmp->cr) || (x2 >= bmp->cr) || (x3 >= bmp->cr)) {
2563          _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color);
2564 	 return;
2565       }
2566 
2567       if ((y1 >= bmp->cb) || (y2 >= bmp->cb) || (y3 >= bmp->cb)) {
2568          _soft_triangle(bmp, x1, y1, x2, y2, x3, y3, color);
2569 	 return;
2570       }
2571    }
2572 
2573    /* sort along the vertical axis */
2574    #define TRI_SWAP(a, b)     \
2575    {                          \
2576       int tmp = x##a;         \
2577       x##a = x##b;            \
2578       x##b = tmp;             \
2579 			      \
2580       tmp = y##a;             \
2581       y##a = y##b;            \
2582       y##b = tmp;             \
2583    }
2584 
2585    if (y2 < y1)
2586       TRI_SWAP(1, 2);
2587 
2588    if (y3 < y1) {
2589       TRI_SWAP(1, 3);
2590       TRI_SWAP(2, 3);
2591    }
2592    else if (y3 < y2)
2593       TRI_SWAP(2, 3);
2594 
2595    SAFISH_CALL(
2596       go_accel();
2597 
2598       if (y2 > y1) {
2599 	 /* draw the top half of the triangle as one trapezoid */
2600 	 trap.y = y1+bmp->y_ofs;
2601 	 trap.count = y2-y1;
2602 	 trap.x1 = trap.x2 = itofix(x1+bmp->x_ofs);
2603 	 trap.slope1 = itofix(x2-x1) / (y2-y1);
2604 	 trap.slope2 = itofix(x3-x1) / (y3-y1);
2605 
2606 	 if (trap.slope1 < 0)
2607 	    trap.x1 += MIN(trap.slope1+itofix(1), 0);
2608 
2609 	 if (trap.slope2 < 0)
2610 	    trap.x2 += MIN(trap.slope2+itofix(1), 0);
2611 
2612 	 if (trap.slope1 > trap.slope2)
2613 	    trap.x1 += MAX(ABS(trap.slope1), itofix(1));
2614 	 else
2615 	    trap.x2 += MAX(ABS(trap.slope2), itofix(1));
2616 
2617 	 af_driver->DrawTrap(af_driver, color, &trap);
2618 
2619 	 if (y3 > y2) {
2620 	    /* draw the bottom half as a second trapezoid */
2621 	    if (trap.slope1 < 0)
2622 	       trap.x1 -= MIN(trap.slope1+itofix(1), 0);
2623 
2624 	    if (trap.slope1 > trap.slope2)
2625 	       trap.x1 -= MAX(ABS(trap.slope1), itofix(1));
2626 
2627 	    trap.count = y3-y2;
2628 	    trap.slope1 = itofix(x3-x2) / (y3-y2);
2629 
2630 	    if (trap.slope1 < 0)
2631 	       trap.x1 += MIN(trap.slope1+itofix(1), 0);
2632 
2633 	    if (trap.x1 > trap.x2)
2634 	       trap.x1 += MAX(ABS(trap.slope1), itofix(1));
2635 
2636 	    af_driver->DrawTrap(af_driver, color, &trap);
2637 	 }
2638       }
2639       else if (y3 > y2) {
2640 	 /* we can draw the entire thing with a single trapezoid */
2641 	 trap.y = y1+bmp->y_ofs;
2642 	 trap.count = y3-y2;
2643 	 trap.x1 = itofix(x2+bmp->x_ofs);
2644 	 trap.x2 = itofix(x1+bmp->x_ofs);
2645 	 trap.slope1 = itofix(x3-x2) / (y3-y2);
2646 	 trap.slope2 = (y3 > y1) ? (itofix(x3-x1) / (y3-y1)) : 0;
2647 
2648 	 if (trap.slope1 < 0)
2649 	    trap.x1 += MIN(trap.slope1+itofix(1), 0);
2650 
2651 	 if (trap.slope2 < 0)
2652 	    trap.x2 += MIN(trap.slope2+itofix(1), 0);
2653 
2654 	 if (trap.x1 > trap.x2)
2655 	    trap.x1 += MAX(ABS(trap.slope1), itofix(1));
2656 	 else
2657 	    trap.x2 += MAX(ABS(trap.slope2), itofix(1));
2658 
2659 	 af_driver->DrawTrap(af_driver, color, &trap);
2660       }
2661    );
2662 }
2663 
2664 
2665 
2666 /* vbeaf_draw_glyph:
2667  *  Monochrome text plotter.
2668  */
vbeaf_draw_glyph(BITMAP * bmp,AL_CONST FONT_GLYPH * glyph,int x,int y,int color,int bg)2669 static void vbeaf_draw_glyph(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg)
2670 {
2671    AL_CONST unsigned char *data = glyph->dat;
2672    int w = glyph->w;
2673    int h = glyph->h;
2674    int stride = (w+7)/8;
2675    int d;
2676 
2677    /* give up if we can't draw this */
2678    if ((x < bmp->cl) || (x+w >= bmp->cr) || ((w&7) && (bg >= 0))) {
2679       orig_draw_glyph(bmp, glyph, x, y, color, bg);
2680       return;
2681    }
2682 
2683    /* clip the top */
2684    if (y < bmp->ct) {
2685       d = bmp->ct - y;
2686 
2687       h -= d;
2688       if (h <= 0)
2689 	 return;
2690 
2691       data += d*stride;
2692       y = bmp->ct;
2693    }
2694 
2695    /* clip the bottom */
2696    if (y+h >= bmp->cb) {
2697       h = bmp->cb - y;
2698       if (h <= 0)
2699 	 return;
2700    }
2701 
2702    SAFE_CALL(
2703       /* set the mix mode */
2704       if (bg >= 0) {
2705 	 af_driver->SetMix(af_driver, 0, 0);
2706 	 d = bg;
2707       }
2708       else {
2709 	 af_driver->SetMix(af_driver, 0, 4);
2710 	 d = 0;
2711       }
2712 
2713       /* draw the letter */
2714       go_accel();
2715 
2716       af_driver->PutMonoImage(af_driver, color, d,
2717 			      x+bmp->x_ofs, y+bmp->y_ofs,
2718 			      stride, 0, 0, stride*8, h, (unsigned char *)data);
2719 
2720       af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2721    );
2722 }
2723 
2724 
2725 
2726 /* vbeaf_draw_sprite:
2727  *  Accelerated sprite drawing routine.
2728  */
vbeaf_draw_sprite(BITMAP * bmp,BITMAP * sprite,int x,int y)2729 static void vbeaf_draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y)
2730 {
2731    int sx, sy, w, h;
2732    int pitch;
2733 
2734    if (((sprite->vtable == &_screen_vtable) && (af_driver->SrcTransBlt)) ||
2735        ((sprite->vtable != &_screen_vtable) && (af_driver->SrcTransBltSys))) {
2736 
2737       /* this sprite can be drawn in hardware */
2738       sx = sprite->x_ofs;
2739       sy = sprite->y_ofs;
2740       w = sprite->w;
2741       h = sprite->h;
2742 
2743       if (bmp->clip) {
2744 	 if (x < bmp->cl) {
2745 	    sx += bmp->cl-x;
2746 	    w -= bmp->cl-x;
2747 	    x = bmp->cl;
2748 	 }
2749 
2750 	 if (y < bmp->ct) {
2751 	    sy += bmp->ct-y;
2752 	    h -= bmp->ct-y;
2753 	    y = bmp->ct;
2754 	 }
2755 
2756 	 if (x+w > bmp->cr)
2757 	    w = bmp->cr-x;
2758 
2759 	 if (w <= 0)
2760 	    return;
2761 
2762 	 if (y+h > bmp->cb)
2763 	    h = bmp->cb-y;
2764 
2765 	 if (h <= 0)
2766 	    return;
2767       }
2768 
2769       if (sprite->vtable == &_screen_vtable) {
2770 	 /* hardware blit within the video memory */
2771 	 SAFISH_CALL(
2772 	    go_accel();
2773 
2774 	    af_driver->SrcTransBlt(af_driver, sx, sy, w, h,
2775 				   x+bmp->x_ofs, y+bmp->y_ofs,
2776 				   0, sprite->vtable->mask_color);
2777 	 );
2778       }
2779       else {
2780 	 /* hardware blit from system memory */
2781 	 if (sprite->h > 1)
2782 	    pitch = (long)sprite->line[1] - (long)sprite->line[0];
2783 	 else
2784 	    pitch = sprite->w;
2785 
2786 	 SAFE_CALL(
2787 	    go_accel();
2788 
2789 	    af_driver->SrcTransBltSys(af_driver,
2790 				      sprite->line[0], pitch,
2791 				      sx, sy, w, h,
2792 				      x+bmp->x_ofs, y+bmp->y_ofs,
2793 				      0, sprite->vtable->mask_color);
2794 	 );
2795       }
2796    }
2797    else {
2798       /* have to use the original software version */
2799       orig_draw_sprite(bmp, sprite, x, y);
2800    }
2801 }
2802 
2803 END_OF_STATIC_FUNCTION(vbeaf_draw_sprite);
2804 
2805 
2806 
2807 /* vbeaf_blit_from_memory:
2808  *  Accelerated system memory -> vram blitting routine.
2809  */
vbeaf_blit_from_memory(BITMAP * source,BITMAP * dest,int source_x,int source_y,int dest_x,int dest_y,int width,int height)2810 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)
2811 {
2812    int pitch;
2813 
2814    if (source->h > 1)
2815       pitch = (long)source->line[1] - (long)source->line[0];
2816    else
2817       pitch = source->w;
2818 
2819    SAFE_CALL(
2820       go_accel();
2821 
2822       af_driver->BitBltSys(af_driver,
2823 			   source->line[0], pitch,
2824 			   source_x, source_y,
2825 			   width, height,
2826 			   dest_x+dest->x_ofs,
2827 			   dest_y+dest->y_ofs,
2828 			   0);
2829    );
2830 }
2831 
2832 END_OF_STATIC_FUNCTION(vbeaf_blit_from_memory);
2833 
2834 
2835 
2836 /* vbeaf_blit_to_self:
2837  *  Accelerated vram -> vram blitting routine.
2838  */
vbeaf_blit_to_self(BITMAP * source,BITMAP * dest,int source_x,int source_y,int dest_x,int dest_y,int width,int height)2839 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)
2840 {
2841    SAFISH_CALL(
2842       go_accel();
2843 
2844       af_driver->BitBlt(af_driver,
2845 			source_x+source->x_ofs,
2846 			source_y+source->y_ofs,
2847 			width, height,
2848 			dest_x+dest->x_ofs,
2849 			dest_y+dest->y_ofs,
2850 			0);
2851    );
2852 }
2853 
2854 
2855 
2856 /* vbeaf_masked_blit:
2857  *  Accelerated masked blitting routine.
2858  */
vbeaf_masked_blit(BITMAP * source,BITMAP * dest,int source_x,int source_y,int dest_x,int dest_y,int width,int height)2859 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)
2860 {
2861    int pitch;
2862 
2863    if ((source->vtable == &_screen_vtable) && (af_driver->SrcTransBlt)) {
2864       /* hardware blit within the video memory */
2865       SAFISH_CALL(
2866 	 go_accel();
2867 
2868 	 af_driver->SrcTransBlt(af_driver,
2869 				source_x+source->x_ofs,
2870 				source_y+source->y_ofs,
2871 				width, height,
2872 				dest_x+dest->x_ofs,
2873 				dest_y+dest->y_ofs,
2874 				0, source->vtable->mask_color);
2875       );
2876    }
2877    else if (af_driver->SrcTransBltSys) {
2878       /* hardware blit from system memory */
2879       if (source->h > 1)
2880 	 pitch = (long)source->line[1] - (long)source->line[0];
2881       else
2882 	 pitch = source->w;
2883 
2884       SAFE_CALL(
2885 	 go_accel();
2886 
2887 	 af_driver->SrcTransBltSys(af_driver,
2888 				   source->line[0], pitch,
2889 				   source_x, source_y,
2890 				   width, height,
2891 				   dest_x+dest->x_ofs,
2892 				   dest_y+dest->y_ofs,
2893 				   0, source->vtable->mask_color);
2894       );
2895    }
2896    else {
2897       /* have to use the original software version */
2898       orig_masked_blit(source, dest, source_x, source_y, dest_x, dest_y, width, height);
2899    }
2900 }
2901 
2902 
2903 
2904 /* vbeaf_clear_to_color:
2905  *  Accelerated screen clear routine.
2906  */
vbeaf_clear_to_color(BITMAP * bitmap,int color)2907 static void vbeaf_clear_to_color(BITMAP *bitmap, int color)
2908 {
2909    SAFISH_CALL(
2910       go_accel();
2911 
2912       if ((vbeaf_fg_mix != 0) || (vbeaf_bg_mix != 0))
2913 	 af_driver->SetMix(af_driver, 0, 0);
2914 
2915       af_driver->DrawRect(af_driver, color,
2916 			  bitmap->cl+bitmap->x_ofs,
2917 			  bitmap->ct+bitmap->y_ofs,
2918 			  bitmap->cr-bitmap->cl,
2919 			  bitmap->cb-bitmap->ct);
2920 
2921       if ((vbeaf_fg_mix != 0) || (vbeaf_bg_mix != 0))
2922 	 af_driver->SetMix(af_driver, vbeaf_fg_mix, vbeaf_bg_mix);
2923    );
2924 }
2925 
2926 
2927 
2928 #endif      /* ifdef VBE/AF is cool on this platform */
2929