1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Video driver for VGA tweaked modes (aka mode-X).
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      Jonathan Tarbox wrote the mode set code.
16  *
17  *      TBD/FeR added the 320x600 and 360x600 modes.
18  *
19  *      See readme.txt for copyright information.
20  */
21 
22 
23 #include <string.h>
24 
25 #include "allegro.h"
26 
27 #ifdef ALLEGRO_GFX_HAS_VGA
28 
29 #include "allegro/internal/aintern.h"
30 #include "allegro/internal/aintvga.h"
31 
32 #ifdef ALLEGRO_INTERNAL_HEADER
33    #include ALLEGRO_INTERNAL_HEADER
34 #endif
35 
36 #include "modexsms.h"
37 
38 #if (!defined ALLEGRO_LINUX) || ((defined ALLEGRO_LINUX_VGA) && ((!defined ALLEGRO_WITH_MODULES) || (defined ALLEGRO_MODULE)))
39 
40 
41 
42 void _x_draw_sprite_end(void);
43 void _x_blit_from_memory_end(void);
44 void _x_blit_to_memory_end(void);
45 
46 static void really_split_modex_screen(int line);
47 
48 
49 
50 /* table of functions for drawing onto the mode-X screen */
51 static GFX_VTABLE __modex_vtable =
52 {
53    8,
54    MASK_COLOR_8,
55    _x_unbank_switch,
56    NULL,
57    NULL,
58    NULL,
59    NULL,
60    NULL,
61    _x_getpixel,
62    _x_putpixel,
63    _x_vline,
64    _x_hline,
65    _x_hline,
66    _normal_line,
67    _fast_line,
68    _normal_rectfill,
69    _soft_triangle,
70    _x_draw_sprite,
71    _x_draw_sprite,
72    _x_draw_sprite_v_flip,
73    _x_draw_sprite_h_flip,
74    _x_draw_sprite_vh_flip,
75    _x_draw_trans_sprite,
76    NULL,
77    _x_draw_lit_sprite,
78    _x_draw_rle_sprite,
79    _x_draw_trans_rle_sprite,
80    NULL,
81    _x_draw_lit_rle_sprite,
82    _x_draw_character,
83    _x_draw_glyph,
84    _x_blit_from_memory,
85    _x_blit_to_memory,
86    _x_blit_from_memory,
87    _x_blit_to_memory,
88    _x_blit,
89    _x_blit_forward,
90    _x_blit_backward,
91    _blit_between_formats,
92    _x_masked_blit,
93    _x_clear_to_color,
94    _pivot_scaled_sprite_flip,
95    NULL,    /* AL_METHOD(void, do_stretch_blit, (struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int masked)); */
96    _soft_draw_gouraud_sprite,
97    _x_draw_sprite_end,
98    _x_blit_from_memory_end,
99    _soft_polygon,
100    _soft_rect,
101    _soft_circle,
102    _soft_circlefill,
103    _soft_ellipse,
104    _soft_ellipsefill,
105    _soft_arc,
106    _soft_spline,
107    _soft_floodfill,
108 
109    _soft_polygon3d,
110    _soft_polygon3d_f,
111    _soft_triangle3d,
112    _soft_triangle3d_f,
113    _soft_quad3d,
114    _soft_quad3d_f
115 };
116 
117 
118 
119 static BITMAP *modex_init(int w, int h, int v_w, int v_h, int color_depth);
120 static void modex_exit(BITMAP *b);
121 static int modex_scroll(int x, int y);
122 static int request_modex_scroll(int x, int y);
123 static int poll_modex_scroll(void);
124 static void modex_enable_triple_buffer(void);
125 static GFX_MODE_LIST *modex_fetch_mode_list(void);
126 
127 
128 
129 GFX_DRIVER gfx_modex =
130 {
131    GFX_MODEX,
132    empty_string,
133    empty_string,
134    "Mode-X",
135    modex_init,
136    modex_exit,
137    modex_scroll,
138    _vga_vsync,
139    _vga_set_palette_range,
140    NULL, NULL,                   /* no triple buffering (yet) */
141    modex_enable_triple_buffer,
142    NULL, NULL, NULL, NULL,       /* no video bitmaps */
143    NULL, NULL,                   /* no system bitmaps */
144    NULL, NULL, NULL, NULL,       /* no hardware cursor */
145    NULL,                         /* no drawing mode hook */
146    _save_vga_mode,
147    _restore_vga_mode,
148    NULL,                         /* AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a)); */
149    modex_fetch_mode_list,
150    0, 0,
151    TRUE,
152    0, 0,
153    0x40000,
154    0,
155    FALSE
156 };
157 
158 
159 
160 static GFX_MODE modex_gfx_modes[] = {
161    { 256, 200, 8 },
162    { 256, 224, 8 },
163    { 256, 240, 8 },
164    { 256, 256, 8 },
165    { 320, 200, 8 },
166    { 320, 240, 8 },
167    { 320, 350, 8 },
168    { 320, 400, 8 },
169    { 320, 480, 8 },
170    { 320, 600, 8 },
171    { 360, 200, 8 },
172    { 360, 240, 8 },
173    { 360, 270, 8 },
174    { 360, 360, 8 },
175    { 360, 400, 8 },
176    { 360, 480, 8 },
177    { 360, 600, 8 },
178    { 376, 282, 8 },
179    { 376, 308, 8 },
180    { 376, 564, 8 },
181    { 400, 150, 8 },
182    { 400, 300, 8 },
183    { 400, 600, 8 },
184    { 0,   0,   0 }
185 };
186 
187 
188 #ifdef GFX_XTENDED
189 
190 
191 static BITMAP *xtended_init(int w, int h, int v_w, int v_h, int color_depth);
192 static GFX_MODE_LIST *xtended_fetch_mode_list(void);
193 
194 
195 GFX_DRIVER gfx_xtended =
196 {
197    GFX_XTENDED,
198    empty_string,
199    empty_string,
200    "Xtended mode",
201    xtended_init,
202    modex_exit,
203    NULL,                         /* no hardware scrolling */
204    _vga_vsync,
205    _vga_set_palette_range,
206    NULL, NULL, NULL,             /* no triple buffering */
207    NULL, NULL, NULL, NULL,       /* no video bitmaps */
208    NULL, NULL,                   /* no system bitmaps */
209    NULL, NULL, NULL, NULL,       /* no hardware cursor */
210    NULL,                         /* no drawing mode hook */
211    NULL, NULL,                   /* no state saving */
212    NULL,                         /* AL_METHOD(void, set_blender_mode, (int mode, int r, int g, int b, int a)); */
213    xtended_fetch_mode_list,
214    640, 400,
215    TRUE,
216    0, 0,
217    0x40000,
218    0,
219    FALSE
220 };
221 
222 
223 
224 GFX_MODE xtended_gfx_modes[] = {
225    { 640, 400, 8 },
226    { 0,   0,   0 }
227 };
228 
229 
230 
231 #endif      /* GFX_XTENDED */
232 
233 
234 
235 /* VGA register contents for the various tweaked modes */
236 typedef struct VGA_REGISTER
237 {
238    unsigned short port;
239    unsigned char index;
240    unsigned char value;
241 } VGA_REGISTER;
242 
243 
244 
245 static VGA_REGISTER mode_256x200[] =
246 {
247    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x3F },
248    { 0x3D4, 0x2,  0x40 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x4E },
249    { 0x3D4, 0x5,  0x96 },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
250    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0x9C },
251    { 0x3D4, 0x11, 0x8E },  { 0x3D4, 0x12, 0x8F },  { 0x3D4, 0x14, 0x0  },
252    { 0x3D4, 0x15, 0x96 },  { 0x3D4, 0x16, 0xB9 },  { 0x3D4, 0x17, 0xE3 },
253    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
254    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
255 };
256 
257 
258 
259 static VGA_REGISTER mode_256x224[] =
260 {
261    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x3F },
262    { 0x3D4, 0x2,  0x40 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x4A },
263    { 0x3D4, 0x5,  0x9A },  { 0x3D4, 0x6,  0xB  },  { 0x3D4, 0x7,  0x3E },
264    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0xDA },
265    { 0x3D4, 0x11, 0x9C },  { 0x3D4, 0x12, 0xBF },  { 0x3D4, 0x14, 0x0  },
266    { 0x3D4, 0x15, 0xC7 },  { 0x3D4, 0x16, 0x4  },  { 0x3D4, 0x17, 0xE3 },
267    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
268    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
269 };
270 
271 
272 
273 static VGA_REGISTER mode_256x240[] =
274 {
275    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x3F },
276    { 0x3D4, 0x2,  0x40 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x4E },
277    { 0x3D4, 0x5,  0x96 },  { 0x3D4, 0x6,  0xD  },  { 0x3D4, 0x7,  0x3E },
278    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0xEA },
279    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xDF },  { 0x3D4, 0x14, 0x0  },
280    { 0x3D4, 0x15, 0xE7 },  { 0x3D4, 0x16, 0x6  },  { 0x3D4, 0x17, 0xE3 },
281    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
282    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
283 };
284 
285 
286 
287 static VGA_REGISTER mode_256x256[] =
288 {
289    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x3F },
290    { 0x3D4, 0x2,  0x40 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x4A },
291    { 0x3D4, 0x5,  0x9A },  { 0x3D4, 0x6,  0x23 },  { 0x3D4, 0x7,  0xB2 },
292    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x61 },  { 0x3D4, 0x10, 0xA  },
293    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xFF },  { 0x3D4, 0x14, 0x0  },
294    { 0x3D4, 0x15, 0x7  },  { 0x3D4, 0x16, 0x1A },  { 0x3D4, 0x17, 0xE3 },
295    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
296    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
297 };
298 
299 
300 
301 static VGA_REGISTER mode_320x200[] =
302 {
303    { 0x3C2, 0x0,  0x63 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x4F },
304    { 0x3D4, 0x2,  0x50 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x54 },
305    { 0x3D4, 0x5,  0x80 },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
306    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0x9C },
307    { 0x3D4, 0x11, 0x8E },  { 0x3D4, 0x12, 0x8F },  { 0x3D4, 0x14, 0x0  },
308    { 0x3D4, 0x15, 0x96 },  { 0x3D4, 0x16, 0xB9 },  { 0x3D4, 0x17, 0xE3 },
309    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
310    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
311 };
312 
313 
314 
315 static VGA_REGISTER mode_320x240[] =
316 {
317    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x4F },
318    { 0x3D4, 0x2,  0x50 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x54 },
319    { 0x3D4, 0x5,  0x80 },  { 0x3D4, 0x6,  0xD  },  { 0x3D4, 0x7,  0x3E },
320    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0xEA },
321    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xDF },  { 0x3D4, 0x14, 0x0  },
322    { 0x3D4, 0x15, 0xE7 },  { 0x3D4, 0x16, 0x6  },  { 0x3D4, 0x17, 0xE3 },
323    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
324    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
325 };
326 
327 
328 
329 static VGA_REGISTER mode_320x400[] =
330 {
331    { 0x3C2, 0x0,  0x63 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x4F },
332    { 0x3D4, 0x2,  0x50 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x54 },
333    { 0x3D4, 0x5,  0x80 },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
334    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0x9C },
335    { 0x3D4, 0x11, 0x8E },  { 0x3D4, 0x12, 0x8F },  { 0x3D4, 0x14, 0x0  },
336    { 0x3D4, 0x15, 0x96 },  { 0x3D4, 0x16, 0xB9 },  { 0x3D4, 0x17, 0xE3 },
337    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
338    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
339 };
340 
341 
342 
343 static VGA_REGISTER mode_320x480[] =
344 {
345    { 0x3C2, 0x0,  0xE3 },  { 0x3D4, 0x0,  0x5F },  { 0x3D4, 0x1,  0x4F },
346    { 0x3D4, 0x2,  0x50 },  { 0x3D4, 0x3,  0x82 },  { 0x3D4, 0x4,  0x54 },
347    { 0x3D4, 0x5,  0x80 },  { 0x3D4, 0x6,  0xD  },  { 0x3D4, 0x7,  0x3E },
348    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0xEA },
349    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xDF },  { 0x3D4, 0x14, 0x0  },
350    { 0x3D4, 0x15, 0xE7 },  { 0x3D4, 0x16, 0x6  },  { 0x3D4, 0x17, 0xE3 },
351    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
352    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
353 };
354 
355 
356 
357 static VGA_REGISTER mode_320x600[] =
358 {
359    { 0x3C2, 0x00, 0xE7 },  { 0x3D4, 0x00, 0x5F },  { 0x3D4, 0x01, 0x4F },
360    { 0x3D4, 0x02, 0x50 },  { 0x3D4, 0x03, 0x82 },  { 0x3D4, 0x04, 0x54 },
361    { 0x3D4, 0x05, 0x80 },  { 0x3D4, 0x06, 0x70 },  { 0x3D4, 0x07, 0xF0 },
362    { 0x3D4, 0x08, 0x00 },  { 0x3D4, 0x09, 0x60 },  { 0x3D4, 0x10, 0x5B },
363    { 0x3D4, 0x11, 0x8C },  { 0x3D4, 0x12, 0x57 },  { 0x3D4, 0x13, 0x28 },
364    { 0x3D4, 0x14, 0x00 },  { 0x3D4, 0x15, 0x58 },  { 0x3D4, 0x16, 0x70 },
365    { 0x3D4, 0x17, 0xE3 },  { 0x3C4, 0x01, 0x01 },  { 0x3C4, 0x04, 0x06 },
366    { 0x3CE, 0x05, 0x40 },  { 0x3CE, 0x06, 0x05 },  { 0x3C0, 0x10, 0x41 },
367    { 0x3C0, 0x13, 0x00 },  { 0,     0,    0    }
368 };
369 
370 
371 
372 static VGA_REGISTER mode_360x200[] =
373 {
374    { 0x3C2, 0x0,  0x67 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
375    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
376    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
377    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0x9C },
378    { 0x3D4, 0x11, 0x8E },  { 0x3D4, 0x12, 0x8F },  { 0x3D4, 0x14, 0x0  },
379    { 0x3D4, 0x15, 0x96 },  { 0x3D4, 0x16, 0xB9 },  { 0x3D4, 0x17, 0xE3 },
380    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
381    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
382 };
383 
384 
385 
386 static VGA_REGISTER mode_360x240[] =
387 {
388    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
389    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
390    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0xD  },  { 0x3D4, 0x7,  0x3E },
391    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x41 },  { 0x3D4, 0x10, 0xEA },
392    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xDF },  { 0x3D4, 0x14, 0x0  },
393    { 0x3D4, 0x15, 0xE7 },  { 0x3D4, 0x16, 0x6  },  { 0x3D4, 0x17, 0xE3 },
394    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
395    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
396 };
397 
398 
399 
400 static VGA_REGISTER mode_360x270[] =
401 {
402    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
403    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
404    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0x30 },  { 0x3D4, 0x7,  0xF0 },
405    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x61 },  { 0x3D4, 0x10, 0x20 },
406    { 0x3D4, 0x11, 0xA9 },  { 0x3D4, 0x12, 0x1B },  { 0x3D4, 0x14, 0x0  },
407    { 0x3D4, 0x15, 0x1F },  { 0x3D4, 0x16, 0x2F },  { 0x3D4, 0x17, 0xE3 },
408    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
409    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
410 };
411 
412 
413 
414 static VGA_REGISTER mode_360x360[] =
415 {
416    { 0x3C2, 0x0,  0x67 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
417    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
418    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
419    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0x88 },
420    { 0x3D4, 0x11, 0x85 },  { 0x3D4, 0x12, 0x67 },  { 0x3D4, 0x14, 0x0  },
421    { 0x3D4, 0x15, 0x6D },  { 0x3D4, 0x16, 0xBA },  { 0x3D4, 0x17, 0xE3 },
422    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
423    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
424 };
425 
426 
427 
428 static VGA_REGISTER mode_360x400[] =
429 {
430    { 0x3C2, 0x0,  0x67 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
431    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
432    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0xBF },  { 0x3D4, 0x7,  0x1F },
433    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0x9C },
434    { 0x3D4, 0x11, 0x8E },  { 0x3D4, 0x12, 0x8F },  { 0x3D4, 0x14, 0x0  },
435    { 0x3D4, 0x15, 0x96 },  { 0x3D4, 0x16, 0xB9 },  { 0x3D4, 0x17, 0xE3 },
436    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
437    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
438 };
439 
440 
441 
442 static VGA_REGISTER mode_360x480[] =
443 {
444    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6B },  { 0x3D4, 0x1,  0x59 },
445    { 0x3D4, 0x2,  0x5A },  { 0x3D4, 0x3,  0x8E },  { 0x3D4, 0x4,  0x5E },
446    { 0x3D4, 0x5,  0x8A },  { 0x3D4, 0x6,  0xD  },  { 0x3D4, 0x7,  0x3E },
447    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0xEA },
448    { 0x3D4, 0x11, 0xAC },  { 0x3D4, 0x12, 0xDF },  { 0x3D4, 0x14, 0x0  },
449    { 0x3D4, 0x15, 0xE7 },  { 0x3D4, 0x16, 0x6  },  { 0x3D4, 0x17, 0xE3 },
450    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
451    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
452 };
453 
454 
455 
456 static VGA_REGISTER mode_360x600[] =
457 {
458    { 0x3C2, 0x00, 0xE7 },  { 0x3D4, 0x00, 0x5F },  { 0x3D4, 0x01, 0x59 },
459    { 0x3D4, 0x02, 0x50 },  { 0x3D4, 0x03, 0x82 },  { 0x3D4, 0x04, 0x54 },
460    { 0x3D4, 0x05, 0x80 },  { 0x3D4, 0x06, 0x70 },  { 0x3D4, 0x07, 0xF0 },
461    { 0x3D4, 0x08, 0x00 },  { 0x3D4, 0x09, 0x60 },  { 0x3D4, 0x10, 0x5B },
462    { 0x3D4, 0x11, 0x8C },  { 0x3D4, 0x12, 0x57 },  { 0x3D4, 0x13, 0x2D },
463    { 0x3D4, 0x14, 0x00 },  { 0x3D4, 0x15, 0x58 },  { 0x3D4, 0x16, 0x70 },
464    { 0x3D4, 0x17, 0xE3 },  { 0x3C4, 0x01, 0x01 },  { 0x3C4, 0x03, 0x00 },
465    { 0x3C4, 0x04, 0x06 },  { 0x3CE, 0x05, 0x40 },  { 0x3CE, 0x06, 0x05 },
466    { 0x3C0, 0x10, 0x41 },  { 0x3C0, 0x11, 0x00 },  { 0x3C0, 0x12, 0x0F },
467    { 0x3C0, 0x13, 0x00 },  { 0x3C0, 0x14, 0x00 },  { 0,     0,    0    }
468 };
469 
470 
471 
472 static VGA_REGISTER mode_376x282[] =
473 {
474    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6E },  { 0x3D4, 0x1,  0x5D },
475    { 0x3D4, 0x2,  0x5E },  { 0x3D4, 0x3,  0x91 },  { 0x3D4, 0x4,  0x62 },
476    { 0x3D4, 0x5,  0x8F },  { 0x3D4, 0x6,  0x62 },  { 0x3D4, 0x7,  0xF0 },
477    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x61 },  { 0x3D4, 0x10, 0x37 },
478    { 0x3D4, 0x11, 0x89 },  { 0x3D4, 0x12, 0x33 },  { 0x3D4, 0x14, 0x0  },
479    { 0x3D4, 0x15, 0x3C },  { 0x3D4, 0x16, 0x5C },  { 0x3D4, 0x17, 0xE3 },
480    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
481    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
482 };
483 
484 
485 
486 static VGA_REGISTER mode_376x308[] =
487 {
488    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6E },  { 0x3D4, 0x1,  0x5D },
489    { 0x3D4, 0x2,  0x5E },  { 0x3D4, 0x3,  0x91 },  { 0x3D4, 0x4,  0x62 },
490    { 0x3D4, 0x5,  0x8F },  { 0x3D4, 0x6,  0x62 },  { 0x3D4, 0x7,  0x0F },
491    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x40 },  { 0x3D4, 0x10, 0x37 },
492    { 0x3D4, 0x11, 0x89 },  { 0x3D4, 0x12, 0x33 },  { 0x3D4, 0x14, 0x0  },
493    { 0x3D4, 0x15, 0x3C },  { 0x3D4, 0x16, 0x5C },  { 0x3D4, 0x17, 0xE3 },
494    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
495    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
496 };
497 
498 
499 
500 static VGA_REGISTER mode_376x564[] =
501 {
502    { 0x3C2, 0x0,  0xE7 },  { 0x3D4, 0x0,  0x6E },  { 0x3D4, 0x1,  0x5D },
503    { 0x3D4, 0x2,  0x5E },  { 0x3D4, 0x3,  0x91 },  { 0x3D4, 0x4,  0x62 },
504    { 0x3D4, 0x5,  0x8F },  { 0x3D4, 0x6,  0x62 },  { 0x3D4, 0x7,  0xF0 },
505    { 0x3D4, 0x8,  0x0  },  { 0x3D4, 0x9,  0x60 },  { 0x3D4, 0x10, 0x37 },
506    { 0x3D4, 0x11, 0x89 },  { 0x3D4, 0x12, 0x33 },  { 0x3D4, 0x14, 0x0  },
507    { 0x3D4, 0x15, 0x3C },  { 0x3D4, 0x16, 0x5C },  { 0x3D4, 0x17, 0xE3 },
508    { 0x3C4, 0x1,  0x1  },  { 0x3CE, 0x5,  0x40 },  { 0x3CE, 0x6,  0x5  },
509    { 0x3C0, 0x10, 0x41 },  { 0,     0,    0    }
510 };
511 
512 
513 
514 static VGA_REGISTER mode_notweak[] =
515 {
516    { 0,     0,    0    }
517 };
518 
519 
520 
521 /* information about a mode-X resolution */
522 typedef struct TWEAKED_MODE
523 {
524    int w, h;
525    VGA_REGISTER *regs;
526    int parent;
527    int hrs;
528    int shift;
529    int repeat;
530 } TWEAKED_MODE;
531 
532 
533 
534 static TWEAKED_MODE xmodes[] =
535 {
536    {  256,  200,  mode_256x200,  0x13, 0, 0, 0  },
537    {  256,  224,  mode_256x224,  0x13, 0, 0, 0  },
538    {  256,  240,  mode_256x240,  0x13, 0, 0, 0  },
539    {  256,  256,  mode_256x256,  0x13, 0, 0, 0  },
540    {  320,  200,  mode_320x200,  0x13, 0, 0, 0  },
541    {  320,  240,  mode_320x240,  0x13, 0, 0, 0  },
542    {  320,  350,  mode_notweak,  0x10, 1, 1, 0  },
543    {  320,  400,  mode_320x400,  0x13, 0, 0, 0  },
544    {  320,  480,  mode_320x480,  0x13, 0, 0, 0  },
545    {  320,  600,  mode_320x600,  0x13, 0, 0, 0  },
546    {  360,  200,  mode_360x200,  0x13, 0, 0, 0  },
547    {  360,  240,  mode_360x240,  0x13, 0, 0, 0  },
548    {  360,  270,  mode_360x270,  0x13, 0, 0, 0  },
549    {  360,  360,  mode_360x360,  0x13, 0, 0, 0  },
550    {  360,  400,  mode_360x400,  0x13, 0, 0, 0  },
551    {  360,  480,  mode_360x480,  0x13, 0, 0, 0  },
552    {  360,  600,  mode_360x600,  0x13, 0, 0, 0  },
553    {  376,  282,  mode_376x282,  0x13, 0, 0, 0  },
554    {  376,  308,  mode_376x308,  0x13, 0, 0, 0  },
555    {  376,  564,  mode_376x564,  0x13, 0, 0, 0  },
556    {  400,  150,  mode_notweak,  0x6A, 1, 1, 3  },
557    {  400,  300,  mode_notweak,  0x6A, 1, 1, 1  },
558    {  400,  600,  mode_notweak,  0x6A, 1, 1, 0  },
559    {  0,    0,    NULL,          0,    0, 0, 0  }
560 };
561 
562 
563 
564 /* lookup tables for use by modexgfx.s */
565 char _x_left_mask_table[] = { 0x00, 0x08, 0x0C, 0x0E, 0x0F };
566 char _x_right_mask_table[] = { 0x00, 0x01, 0x03, 0x07, 0x0F };
567 
568 
569 
570 /* memory buffer for emulating linear access to a mode-X screen */
571 unsigned long _x_magic_buffer_addr = 0;
572 unsigned long _x_magic_screen_addr = 0;
573 int _x_magic_screen_width = 0;
574 
575 #ifdef ALLEGRO_DOS
576    static int magic_sel = 0;
577 #endif
578 
579 
580 
581 /* setup_x_magic:
582  *  To make sure that things will go on working properly even if a few
583  *  bits of code don't know about mode-X screens, we do special magic
584  *  inside the bank switch functions to emulate a linear image surface.
585  *  Whenever someone tries to access the screen directly, these routines
586  *  copy the planar image into a temporary buffer, let the client write
587  *  there, and then automatically refresh the screen with the updated
588  *  graphics. Very slow, but it makes 100% sure that everything will work.
589  */
setup_x_magic(BITMAP * b)590 static void setup_x_magic(BITMAP *b)
591 {
592    #ifdef ALLEGRO_DOS
593 
594       /* DOS buffer has to go in conventional memory */
595       int seg = __dpmi_allocate_dos_memory((b->w+15)/16, &magic_sel);
596 
597       if (seg > 0)
598 	 _x_magic_buffer_addr = seg*16;
599       else
600 	 _x_magic_buffer_addr = 0;
601 
602    #else
603 
604       /* other platforms can put the buffer wherever they like */
605       _x_magic_buffer_addr = (unsigned long)_AL_MALLOC(b->w);
606 
607    #endif
608 
609    _x_magic_screen_addr = 0;
610    _x_magic_screen_width = 0;
611 
612    LOCK_VARIABLE(_x_magic_buffer_addr);
613    LOCK_VARIABLE(_x_magic_screen_addr);
614    LOCK_VARIABLE(_x_magic_screen_width);
615    LOCK_FUNCTION(_x_bank_switch);
616 
617    b->write_bank = b->read_bank = _x_bank_switch;
618 }
619 
620 
621 
622 /* modex_exit:
623  *  Frees the magic bank switch buffer.
624  */
modex_exit(BITMAP * b)625 static void modex_exit(BITMAP *b)
626 {
627    #ifdef ALLEGRO_DOS
628 
629       /* free conventional memory buffer */
630       if (_x_magic_buffer_addr) {
631 	 __dpmi_free_dos_memory(magic_sel);
632 	 magic_sel = 0;
633 	 _x_magic_buffer_addr = 0;
634       }
635 
636    #else
637 
638       /* free normal memory buffer */
639       if (_x_magic_buffer_addr) {
640 	 _AL_FREE((void *)_x_magic_buffer_addr);
641 	 _x_magic_buffer_addr = 0;
642       }
643 
644    #endif
645    _unset_vga_mode();
646 
647    /* see modexsms.c */
648    _split_modex_screen_ptr = NULL;
649 }
650 
651 
652 
653 /* modex_init:
654  *  Selects a tweaked VGA mode and creates a screen bitmap for it.
655  */
modex_init(int w,int h,int v_w,int v_h,int color_depth)656 static BITMAP *modex_init(int w, int h, int v_w, int v_h, int color_depth)
657 {
658    TWEAKED_MODE *mode = xmodes;
659    VGA_REGISTER *reg;
660    BITMAP *b;
661    unsigned long addr;
662    int c;
663 
664    /* Do not continue if this version of Allegro was built in C-only mode.
665     * The bank switchers assume asm-mode calling conventions, but the
666     * library would try to call them with C calling conventions.
667     */
668 #ifdef ALLEGRO_NO_ASM
669    return NULL;
670 #endif
671 
672    /* see modexsms.c */
673    _split_modex_screen_ptr = really_split_modex_screen;
674 
675    /* check it is a valid resolution */
676    if (color_depth != 8) {
677       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Mode-X only supports 8 bit color"));
678       return NULL;
679    }
680 
681    /* search the mode table for the requested resolution */
682    while ((mode->regs) && ((mode->w != w) || (mode->h != h)))
683       mode++;
684 
685    if (!mode->regs) {
686       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not a VGA mode-X resolution"));
687       return NULL;
688    }
689 
690    /* round up virtual size if required (v_w must be a multiple of eight) */
691    v_w = MAX(w, (v_w+7) & 0xFFF8);
692    v_h = MAX(h, v_h);
693 
694    if (v_h > 0x40000/v_w) {
695       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Virtual screen size too large"));
696       return NULL;
697    }
698 
699    /* calculate virtual height = vram / width */
700    v_h = 0x40000 / v_w;
701 
702    /* lock everything that is used to draw mouse pointers */
703    LOCK_VARIABLE(__modex_vtable);
704    LOCK_FUNCTION(_x_draw_sprite);
705    LOCK_FUNCTION(_x_blit_from_memory);
706    LOCK_FUNCTION(_x_blit_to_memory);
707 
708    /* set the base video mode, then start tweaking things */
709    addr = _set_vga_mode(mode->parent);
710    if (!addr)
711       return NULL;
712 
713    outportw(0x3C4, 0x0100);                     /* synchronous reset */
714 
715    outportb(0x3D4, 0x11);                       /* enable crtc regs 0-7 */
716    outportb(0x3D5, inportb(0x3D5) & 0x7F);
717 
718    outportw(0x3C4, 0x0604);                     /* disable chain-4 */
719 
720    for (reg=mode->regs; reg->port; reg++) {     /* set the VGA registers */
721       if (reg->port == 0x3C0) {
722 	 inportb(0x3DA);
723 	 outportb(0x3C0, reg->index | 0x20);
724 	 outportb(0x3C0, reg->value);
725       }
726       else if (reg->port == 0x3C2) {
727 	 outportb(reg->port, reg->value);
728       }
729       else {
730 	 outportb(reg->port, reg->index);
731 	 outportb(reg->port+1, reg->value);
732       }
733    }
734 
735    if (mode->hrs) {
736       outportb(0x3D4, 0x11);
737       outportb(0x3D5, inportb(0x3D5)&0x7F);
738       outportb(0x3D4, 0x04);
739       outportb(0x3D5, inportb(0x3D5)+mode->hrs);
740       outportb(0x3D4, 0x11);
741       outportb(0x3D5,inportb(0x3D5)|0x80);
742    }
743 
744    if (mode->shift) {
745       outportb(0x3CE, 0x05);
746       outportb(0x3CF, (inportb(0x3CF)&0x60)|0x40);
747 
748       inportb(0x3DA);
749       outportb(0x3C0, 0x30);
750       outportb(0x3C0, inportb(0x3C1)|0x40);
751 
752       for (c=0; c<16; c++) {
753 	 outportb(0x3C0, c);
754 	 outportb(0x3C0, c);
755       }
756       outportb(0x3C0, 0x20);
757    }
758 
759    if (mode->repeat) {
760       outportb(0x3D4, 0x09);
761       outportb(0x3D5,(inportb(0x3D5)&0x60)|mode->repeat);
762    }
763 
764    outportb(0x3D4, 0x13);                       /* set scanline length */
765    outportb(0x3D5, v_w/8);
766 
767    outportw(0x3C4, 0x0300);                     /* restart sequencer */
768 
769    /* We only use 1/4th of the real width for the bitmap line pointers,
770     * so they can be used directly for writing to vram, eg. the address
771     * for pixel(x,y) is bmp->line[y]+(x/4). Divide the x coordinate, but
772     * not the line pointer. The clipping position and bitmap width are
773     * stored in the linear pixel format, though, not as mode-X planes.
774     */
775    b = _make_bitmap(v_w/4, v_h, addr, &gfx_modex, 8, v_w/4);
776    if (!b)
777       return NULL;
778 
779    b->w = b->cr = v_w;
780    b->vtable = &__modex_vtable;
781    b->id |= BMP_ID_PLANAR;
782 
783    setup_x_magic(b);
784 
785    gfx_modex.w = w;
786    gfx_modex.h = h;
787 
788    if (_timer_use_retrace) {
789       gfx_modex.request_scroll = request_modex_scroll;
790       gfx_modex.poll_scroll = poll_modex_scroll;
791    }
792    else {
793       gfx_modex.request_scroll = NULL;
794       gfx_modex.poll_scroll = NULL;
795    }
796 
797    #ifdef ALLEGRO_LINUX
798 
799       b->vtable->acquire = __al_linux_acquire_bitmap;
800       b->vtable->release = __al_linux_release_bitmap;
801 
802    #endif
803 
804    return b;
805 }
806 
807 
808 
809 #ifdef GFX_XTENDED
810 
811 
812 /* xtended_init:
813  *  Selects the unchained 640x400 mode.
814  */
xtended_init(int w,int h,int v_w,int v_h,int color_depth)815 static BITMAP *xtended_init(int w, int h, int v_w, int v_h, int color_depth)
816 {
817    unsigned long addr;
818    BITMAP *b;
819 
820    /* Do not continue if this version of Allegro was built in C-only mode.
821     * The bank switchers assume asm-mode calling conventions, but the
822     * library would try to call them with C calling conventions.
823     */
824 #ifdef ALLEGRO_NO_ASM
825    return NULL;
826 #endif
827 
828    /* see modexsms.c */
829    _split_modex_screen_ptr = really_split_modex_screen;
830 
831    /* check it is a valid resolution */
832    if (color_depth != 8) {
833       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Xtended mode only supports 8 bit color"));
834       return NULL;
835    }
836 
837    if ((w != 640) || (h != 400) || (v_w > 640) || (v_h > 400)) {
838       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Xtended mode only supports 640x400"));
839       return NULL;
840    }
841 
842    /* lock everything that is used to draw mouse pointers */
843    LOCK_VARIABLE(__modex_vtable);
844    LOCK_FUNCTION(_x_draw_sprite);
845    LOCK_FUNCTION(_x_blit_from_memory);
846    LOCK_FUNCTION(_x_blit_to_memory);
847 
848    /* set VESA mode 0x100 */
849    addr = _set_vga_mode(0x100);
850 
851    if (!addr) {
852       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("VESA mode 0x100 not available"));
853       return NULL;
854    }
855 
856    outportw(0x3C4, 0x0604);         /* disable chain-4 */
857 
858    /* we only use 1/4th of the width for the bitmap line pointers */
859    b = _make_bitmap(640/4, 400, addr, &gfx_xtended, 8, 640/4);
860    if (!b)
861       return NULL;
862 
863    b->w = b->cr = 640;
864    b->vtable = &__modex_vtable;
865    b->id |= BMP_ID_PLANAR;
866 
867    setup_x_magic(b);
868 
869    return b;
870 }
871 
872 
873 
874 /* xtended_fetch_mode_list:
875  *  Creates a list of of currently implemented Xtended modes.
876  */
xtended_fetch_mode_list(void)877 static GFX_MODE_LIST *xtended_fetch_mode_list(void)
878 {
879    GFX_MODE_LIST *mode_list;
880 
881    mode_list = _AL_MALLOC(sizeof(GFX_MODE_LIST));
882    if (!mode_list) return NULL;
883 
884    mode_list->mode = _AL_MALLOC(sizeof(xtended_gfx_modes));
885    if (!mode_list->mode) return NULL;
886 
887    memcpy(mode_list->mode, xtended_gfx_modes, sizeof(xtended_gfx_modes));
888    mode_list->num_modes = sizeof(xtended_gfx_modes) / sizeof(GFX_MODE) - 1;
889 
890    return mode_list;
891 }
892 
893 #endif      /* GFX_XTENDED */
894 
895 
896 
897 /* modex_scroll:
898  *  Hardware scrolling routine for mode-X.
899  */
modex_scroll(int x,int y)900 static int modex_scroll(int x, int y)
901 {
902    long a = x + (y * VIRTUAL_W);
903 
904    DISABLE();
905 
906    _vsync_out_h();
907 
908    /* write to VGA address registers */
909    _write_vga_register(_crtc, 0x0D, (a>>2) & 0xFF);
910    _write_vga_register(_crtc, 0x0C, (a>>10) & 0xFF);
911 
912    ENABLE();
913 
914    /* write low 2 bits to horizontal pan register */
915    _write_hpp((a&3)<<1);
916 
917    return 0;
918 }
919 
920 
921 
922 /* request_modex_scroll:
923  *  Requests a scroll but doesn't wait for it to be competed: just writes
924  *  to some VGA registers and some variables used by the vertical retrace
925  *  interrupt simulator, and then returns immediately. The scroll will
926  *  actually take place during the next vertical retrace, so this function
927  *  can be used together with poll_modex_scroll to implement triple buffered
928  *  animation systems (see examples/ex20.c).
929  */
request_modex_scroll(int x,int y)930 static int request_modex_scroll(int x, int y)
931 {
932    long a = x + (y * VIRTUAL_W);
933 
934    DISABLE();
935 
936    _vsync_out_h();
937 
938    /* write to VGA address registers */
939    _write_vga_register(_crtc, 0x0D, (a>>2) & 0xFF);
940    _write_vga_register(_crtc, 0x0C, (a>>10) & 0xFF);
941 
942    ENABLE();
943 
944    if (_timer_use_retrace) {
945       /* store low 2 bits where the timer handler will find them */
946       _retrace_hpp_value = (a&3)<<1;
947    }
948    else {
949       /* change instantly */
950       _write_hpp((a&3)<<1);
951    }
952 
953    return 0;
954 }
955 
956 
957 
958 /* poll_modex_scroll:
959  *  Returns non-zero if there is a scroll waiting to take place, previously
960  *  set by request_modex_scroll(). Only works if vertical retrace interrupts
961  *  are enabled.
962  */
poll_modex_scroll(void)963 static int poll_modex_scroll(void)
964 {
965    if ((_retrace_hpp_value < 0) || (!_timer_use_retrace))
966       return FALSE;
967 
968    return TRUE;
969 }
970 
971 
972 
973 /* modex_enable_triple_buffer:
974  *  Tries to turn on triple buffering mode, if that is currently possible.
975  */
modex_enable_triple_buffer(void)976 static void modex_enable_triple_buffer(void)
977 {
978    if ((!_timer_use_retrace) && (timer_can_simulate_retrace()))
979       timer_simulate_retrace(TRUE);
980 
981    if (_timer_use_retrace) {
982       gfx_modex.request_scroll = request_modex_scroll;
983       gfx_modex.poll_scroll = poll_modex_scroll;
984    }
985 }
986 
987 
988 
989 /* x_write:
990  *  Inline helper for the C drawing functions: writes a pixel onto a
991  *  mode-X bitmap, performing clipping but ignoring the drawing mode.
992  */
x_write(BITMAP * bmp,int x,int y,int color)993 static INLINE void x_write(BITMAP *bmp, int x, int y, int color)
994 {
995    if ((x >= bmp->cl) && (x < bmp->cr) && (y >= bmp->ct) && (y < bmp->cb)) {
996       outportw(0x3C4, (0x100<<(x&3))|2);
997       bmp_write8((unsigned long)bmp->line[y]+(x>>2), color);
998    }
999 }
1000 
1001 
1002 
1003 /* _x_vline:
1004  *  Draws a vertical line onto a mode-X screen.
1005  */
_x_vline(BITMAP * bmp,int x,int y1,int y2,int color)1006 void _x_vline(BITMAP *bmp, int x, int y1, int y2, int color)
1007 {
1008    int c;
1009 
1010    if (y1 > y2) {
1011       c = y1;
1012       y1 = y2;
1013       y2 = c;
1014    }
1015 
1016    for (c=y1; c<=y2; c++)
1017       _x_putpixel(bmp, x, c, color);
1018 }
1019 
1020 
1021 
1022 /* _x_draw_sprite_v_flip:
1023  *  Draws a vertically flipped sprite onto a mode-X screen.
1024  */
_x_draw_sprite_v_flip(BITMAP * bmp,BITMAP * sprite,int x,int y)1025 void _x_draw_sprite_v_flip(BITMAP *bmp, BITMAP *sprite, int x, int y)
1026 {
1027    int c1, c2;
1028 
1029    bmp_select(bmp);
1030 
1031    for (c1=0; c1<sprite->h; c1++)
1032       for (c2=0; c2<sprite->w; c2++)
1033 	 if (sprite->line[sprite->h-1-c1][c2])
1034 	    x_write(bmp, x+c2, y+c1, sprite->line[sprite->h-1-c1][c2]);
1035 }
1036 
1037 
1038 
1039 /* _x_draw_sprite_h_flip:
1040  *  Draws a horizontally flipped sprite onto a mode-X screen.
1041  */
_x_draw_sprite_h_flip(BITMAP * bmp,BITMAP * sprite,int x,int y)1042 void _x_draw_sprite_h_flip(BITMAP *bmp, BITMAP *sprite, int x, int y)
1043 {
1044    int c1, c2;
1045 
1046    bmp_select(bmp);
1047 
1048    for (c1=0; c1<sprite->h; c1++)
1049       for (c2=0; c2<sprite->w; c2++)
1050 	 if (sprite->line[c1][sprite->w-1-c2])
1051 	    x_write(bmp, x+c2, y+c1, sprite->line[c1][sprite->w-1-c2]);
1052 }
1053 
1054 
1055 
1056 /* _x_draw_sprite_vh_flip:
1057  *  Draws a diagonally flipped sprite onto a mode-X screen.
1058  */
_x_draw_sprite_vh_flip(BITMAP * bmp,BITMAP * sprite,int x,int y)1059 void _x_draw_sprite_vh_flip(BITMAP *bmp, BITMAP *sprite, int x, int y)
1060 {
1061    int c1, c2;
1062 
1063    bmp_select(bmp);
1064 
1065    for (c1=0; c1<sprite->h; c1++)
1066       for (c2=0; c2<sprite->w; c2++)
1067 	 if (sprite->line[sprite->h-1-c1][sprite->w-1-c2])
1068 	    x_write(bmp, x+c2, y+c1, sprite->line[sprite->h-1-c1][sprite->w-1-c2]);
1069 }
1070 
1071 
1072 
1073 /* _x_draw_trans_sprite:
1074  *  Draws a translucent sprite onto a mode-X screen.
1075  */
_x_draw_trans_sprite(BITMAP * bmp,BITMAP * sprite,int x,int y)1076 void _x_draw_trans_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y)
1077 {
1078    int sx, sy, sy2;
1079    int dx, dy;
1080    int xlen, ylen;
1081    int plane;
1082    unsigned char *src;
1083    unsigned long addr;
1084 
1085    sx = sy = 0;
1086 
1087    if (bmp->clip) {
1088       if (x < bmp->cl) {
1089 	 sx = bmp->cl - x;
1090 	 x = bmp->cl;
1091       }
1092       if (y < bmp->ct) {
1093 	 sy = bmp->ct - y;
1094 	 y = bmp->ct;
1095       }
1096       xlen = MIN(sprite->w - sx, bmp->cr - x);
1097       ylen = MIN(sprite->h - sy, bmp->cb - y);
1098    }
1099    else {
1100       xlen = sprite->w;
1101       ylen = sprite->h;
1102    }
1103 
1104    if ((xlen <= 0) || (ylen <= 0))
1105       return;
1106 
1107    bmp_select(bmp);
1108 
1109    sy2 = sy;
1110 
1111    for (plane=0; plane<4; plane++) {
1112       sy = sy2;
1113 
1114       outportw(0x3C4, (0x100<<((x+plane)&3))|2);
1115       outportw(0x3CE, (((x+plane)&3)<<8)|4);
1116 
1117       for (dy=0; dy<ylen; dy++) {
1118 	 src = sprite->line[sy]+sx+plane;
1119 	 addr = (unsigned long)bmp->line[y+dy]+((x+plane)>>2);
1120 
1121 	 for (dx=plane; dx<xlen; dx+=4) {
1122 	    bmp_write8(addr, color_map->data[*src][bmp_read8(addr)]);
1123 
1124 	    addr++;
1125 	    src+=4;
1126 	 }
1127 
1128 	 sy++;
1129       }
1130    }
1131 }
1132 
1133 
1134 
1135 /* _x_draw_lit_sprite:
1136  *  Draws a lit sprite onto a mode-X screen.
1137  */
_x_draw_lit_sprite(BITMAP * bmp,BITMAP * sprite,int x,int y,int color)1138 void _x_draw_lit_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int color)
1139 {
1140    int sx, sy, sy2;
1141    int dx, dy;
1142    int xlen, ylen;
1143    int plane;
1144    unsigned char *src;
1145    unsigned long addr;
1146 
1147    sx = sy = 0;
1148 
1149    if (bmp->clip) {
1150       if (x < bmp->cl) {
1151 	 sx = bmp->cl - x;
1152 	 x = bmp->cl;
1153       }
1154       if (y < bmp->ct) {
1155 	 sy = bmp->ct - y;
1156 	 y = bmp->ct;
1157       }
1158       xlen = MIN(sprite->w - sx, bmp->cr - x);
1159       ylen = MIN(sprite->h - sy, bmp->cb - y);
1160    }
1161    else {
1162       xlen = sprite->w;
1163       ylen = sprite->h;
1164    }
1165 
1166    if ((xlen <= 0) || (ylen <= 0))
1167       return;
1168 
1169    bmp_select(bmp);
1170 
1171    sy2 = sy;
1172 
1173    for (plane=0; plane<4; plane++) {
1174       sy = sy2;
1175 
1176       outportw(0x3C4, (0x100<<((x+plane)&3))|2);
1177 
1178       for (dy=0; dy<ylen; dy++) {
1179 	 src = sprite->line[sy]+sx+plane;
1180 	 addr = (unsigned long)bmp->line[y+dy]+((x+plane)>>2);
1181 
1182 	 for (dx=plane; dx<xlen; dx+=4) {
1183 	    if (*src)
1184 	       bmp_write8(addr, color_map->data[color][*src]);
1185 
1186 	    addr++;
1187 	    src+=4;
1188 	 }
1189 
1190 	 sy++;
1191       }
1192    }
1193 }
1194 
1195 
1196 
1197 /* _x_draw_rle_sprite:
1198  *  Draws an RLE sprite onto a mode-X screen.
1199  */
_x_draw_rle_sprite(BITMAP * bmp,AL_CONST RLE_SPRITE * sprite,int x,int y)1200 void _x_draw_rle_sprite(BITMAP *bmp, AL_CONST RLE_SPRITE *sprite, int x, int y)
1201 {
1202    AL_CONST signed char *p = sprite->dat;
1203    int c;
1204    int x_pos, y_pos;
1205    int lgap, width;
1206    unsigned long addr;
1207 
1208    bmp_select(bmp);
1209    y_pos = 0;
1210 
1211    /* clip on the top */
1212    while (y+y_pos < bmp->ct) {
1213       y_pos++;
1214       if ((y_pos >= sprite->h) || (y+y_pos >= bmp->cb))
1215 	 return;
1216 
1217       while (*p)
1218 	 p++;
1219 
1220       p++;
1221    }
1222 
1223    /* x axis clip */
1224    lgap = MAX(bmp->cl-x, 0);
1225    width = MIN(sprite->w, bmp->cr-x);
1226    if (width <= lgap)
1227       return;
1228 
1229    /* draw it */
1230    while ((y_pos<sprite->h) && (y+y_pos < bmp->cb)) {
1231       addr = (unsigned long)bmp->line[y+y_pos];
1232       x_pos = 0;
1233       c = *(p++);
1234 
1235       /* skip pixels on the left */
1236       while (x_pos < lgap) {
1237 	 if (c > 0) {
1238 	    /* skip a run of solid pixels */
1239 	    if (c > lgap-x_pos) {
1240 	       p += lgap-x_pos;
1241 	       c -= lgap-x_pos;
1242 	       x_pos = lgap;
1243 	       break;
1244 	    }
1245 
1246 	    x_pos += c;
1247 	    p += c;
1248 	 }
1249 	 else {
1250 	    /* skip a run of zeros */
1251 	    if (-c > lgap-x_pos) {
1252 	       c += lgap-x_pos;
1253 	       x_pos = lgap;
1254 	       break;
1255 	    }
1256 
1257 	    x_pos -= c;
1258 	 }
1259 
1260 	 c = *(p++);
1261       }
1262 
1263       /* draw a line of the sprite */
1264       for (;;) {
1265 	 if (c > 0) {
1266 	    /* draw a run of solid pixels */
1267 	    c = MIN(c, width-x_pos);
1268 	    while (c > 0) {
1269 	       outportw(0x3C4, (0x100<<((x+x_pos)&3))|2);
1270 	       bmp_write8(addr+((x+x_pos)>>2), *p);
1271 	       x_pos++;
1272 	       p++;
1273 	       c--;
1274 	    }
1275 	 }
1276 	 else {
1277 	    /* skip a run of zeros */
1278 	    x_pos -= c;
1279 	 }
1280 
1281 	 if (x_pos < width)
1282 	    c = (*p++);
1283 	 else
1284 	    break;
1285       }
1286 
1287       /* skip pixels on the right */
1288       if (x_pos < sprite->w) {
1289 	 while (*p)
1290 	    p++;
1291 
1292 	 p++;
1293       }
1294 
1295       y_pos++;
1296    }
1297 }
1298 
1299 
1300 
1301 /* _x_draw_trans_rle_sprite:
1302  *  Draws an RLE sprite onto a mode-X screen.
1303  */
_x_draw_trans_rle_sprite(BITMAP * bmp,AL_CONST RLE_SPRITE * sprite,int x,int y)1304 void _x_draw_trans_rle_sprite(BITMAP *bmp, AL_CONST RLE_SPRITE *sprite, int x, int y)
1305 {
1306    AL_CONST signed char *p = sprite->dat;
1307    int c;
1308    int x_pos, y_pos;
1309    int lgap, width;
1310    unsigned long addr, a;
1311 
1312    bmp_select(bmp);
1313    y_pos = 0;
1314 
1315    /* clip on the top */
1316    while (y+y_pos < bmp->ct) {
1317       y_pos++;
1318       if ((y_pos >= sprite->h) || (y+y_pos >= bmp->cb))
1319 	 return;
1320 
1321       while (*p)
1322 	 p++;
1323 
1324       p++;
1325    }
1326 
1327    /* x axis clip */
1328    lgap = MAX(bmp->cl-x, 0);
1329    width = MIN(sprite->w, bmp->cr-x);
1330    if (width <= lgap)
1331       return;
1332 
1333    /* draw it */
1334    while ((y_pos<sprite->h) && (y+y_pos < bmp->cb)) {
1335       addr = (unsigned long)bmp->line[y+y_pos];
1336       x_pos = 0;
1337       c = *(p++);
1338 
1339       /* skip pixels on the left */
1340       while (x_pos < lgap) {
1341 	 if (c > 0) {
1342 	    /* skip a run of solid pixels */
1343 	    if (c > lgap-x_pos) {
1344 	       p += lgap-x_pos;
1345 	       c -= lgap-x_pos;
1346 	       x_pos = lgap;
1347 	       break;
1348 	    }
1349 
1350 	    x_pos += c;
1351 	    p += c;
1352 	 }
1353 	 else {
1354 	    /* skip a run of zeros */
1355 	    if (-c > lgap-x_pos) {
1356 	       c += lgap-x_pos;
1357 	       x_pos = lgap;
1358 	       break;
1359 	    }
1360 
1361 	    x_pos -= c;
1362 	 }
1363 
1364 	 c = *(p++);
1365       }
1366 
1367       /* draw a line of the sprite */
1368       for (;;) {
1369 	 if (c > 0) {
1370 	    /* draw a run of solid pixels */
1371 	    c = MIN(c, width-x_pos);
1372 	    while (c > 0) {
1373 	       outportw(0x3C4, (0x100<<((x+x_pos)&3))|2);
1374 	       outportw(0x3CE, (((x+x_pos)&3)<<8)|4);
1375 	       a = addr+((x+x_pos)>>2);
1376 	       bmp_write8(a, color_map->data[*p][bmp_read8(a)]);
1377 	       x_pos++;
1378 	       p++;
1379 	       c--;
1380 	    }
1381 	 }
1382 	 else {
1383 	    /* skip a run of zeros */
1384 	    x_pos -= c;
1385 	 }
1386 
1387 	 if (x_pos < width)
1388 	    c = (*p++);
1389 	 else
1390 	    break;
1391       }
1392 
1393       /* skip pixels on the right */
1394       if (x_pos < sprite->w) {
1395 	 while (*p)
1396 	    p++;
1397 
1398 	 p++;
1399       }
1400 
1401       y_pos++;
1402    }
1403 }
1404 
1405 
1406 
1407 /* _x_draw_lit_rle_sprite:
1408  *  Draws a tinted RLE sprite onto a mode-X screen.
1409  */
_x_draw_lit_rle_sprite(BITMAP * bmp,AL_CONST RLE_SPRITE * sprite,int x,int y,int color)1410 void _x_draw_lit_rle_sprite(BITMAP *bmp, AL_CONST RLE_SPRITE *sprite, int x, int y, int color)
1411 {
1412    AL_CONST signed char *p = sprite->dat;
1413    int c;
1414    int x_pos, y_pos;
1415    int lgap, width;
1416    unsigned long addr;
1417 
1418    bmp_select(bmp);
1419    y_pos = 0;
1420 
1421    /* clip on the top */
1422    while (y+y_pos < bmp->ct) {
1423       y_pos++;
1424       if ((y_pos >= sprite->h) || (y+y_pos >= bmp->cb))
1425 	 return;
1426 
1427       while (*p)
1428 	 p++;
1429 
1430       p++;
1431    }
1432 
1433    /* x axis clip */
1434    lgap = MAX(bmp->cl-x, 0);
1435    width = MIN(sprite->w, bmp->cr-x);
1436    if (width <= lgap)
1437       return;
1438 
1439    /* draw it */
1440    while ((y_pos<sprite->h) && (y+y_pos < bmp->cb)) {
1441       addr = (unsigned long)bmp->line[y+y_pos];
1442       x_pos = 0;
1443       c = *(p++);
1444 
1445       /* skip pixels on the left */
1446       while (x_pos < lgap) {
1447 	 if (c > 0) {
1448 	    /* skip a run of solid pixels */
1449 	    if (c > lgap-x_pos) {
1450 	       p += lgap-x_pos;
1451 	       c -= lgap-x_pos;
1452 	       x_pos = lgap;
1453 	       break;
1454 	    }
1455 
1456 	    x_pos += c;
1457 	    p += c;
1458 	 }
1459 	 else {
1460 	    /* skip a run of zeros */
1461 	    if (-c > lgap-x_pos) {
1462 	       c += lgap-x_pos;
1463 	       x_pos = lgap;
1464 	       break;
1465 	    }
1466 
1467 	    x_pos -= c;
1468 	 }
1469 
1470 	 c = *(p++);
1471       }
1472 
1473       /* draw a line of the sprite */
1474       for (;;) {
1475 	 if (c > 0) {
1476 	    /* draw a run of solid pixels */
1477 	    c = MIN(c, width-x_pos);
1478 	    while (c > 0) {
1479 	       outportw(0x3C4, (0x100<<((x+x_pos)&3))|2);
1480 	       bmp_write8(addr+((x+x_pos)>>2), color_map->data[color][*p]);
1481 	       x_pos++;
1482 	       p++;
1483 	       c--;
1484 	    }
1485 	 }
1486 	 else {
1487 	    /* skip a run of zeros */
1488 	    x_pos -= c;
1489 	 }
1490 
1491 	 if (x_pos < width)
1492 	    c = (*p++);
1493 	 else
1494 	    break;
1495       }
1496 
1497       /* skip pixels on the right */
1498       if (x_pos < sprite->w) {
1499 	 while (*p)
1500 	    p++;
1501 
1502 	 p++;
1503       }
1504 
1505       y_pos++;
1506    }
1507 }
1508 
1509 
1510 
1511 /* _x_draw_character:
1512  *  Draws a character from a proportional font onto a mode-X screen.
1513  */
_x_draw_character(BITMAP * bmp,BITMAP * sprite,int x,int y,int color,int bg)1514 void _x_draw_character(BITMAP *bmp, BITMAP *sprite, int x, int y, int color, int bg)
1515 {
1516    int c1, c2;
1517 
1518    bmp_select(bmp);
1519 
1520    for (c1=0; c1<sprite->h; c1++) {
1521       for (c2=0; c2<sprite->w; c2++) {
1522 	 if (sprite->line[c1][c2])
1523 	    x_write(bmp, x+c2, y+c1, color);
1524 	 else {
1525 	    if (bg >= 0)
1526 	       x_write(bmp, x+c2, y+c1, bg);
1527 	 }
1528       }
1529    }
1530 }
1531 
1532 
1533 
1534 /* _x_draw_glyph:
1535  *  Draws monochrome text onto a mode-X screen.
1536  */
_x_draw_glyph(BITMAP * bmp,AL_CONST FONT_GLYPH * glyph,int x,int y,int color,int bg)1537 void _x_draw_glyph(BITMAP *bmp, AL_CONST FONT_GLYPH *glyph, int x, int y, int color, int bg)
1538 {
1539    AL_CONST unsigned char *data = glyph->dat;
1540    AL_CONST unsigned char *dat;
1541    unsigned long addr;
1542    int w = glyph->w;
1543    int h = glyph->h;
1544    int stride = (w+7)/8;
1545    int lgap = 0;
1546    int plane, d, i, j, k;
1547 
1548    if (bmp->clip) {
1549       /* clip the top */
1550       if (y < bmp->ct) {
1551 	 d = bmp->ct - y;
1552 
1553 	 h -= d;
1554 	 if (h <= 0)
1555 	    return;
1556 
1557 	 data += d*stride;
1558 	 y = bmp->ct;
1559       }
1560 
1561       /* clip the bottom */
1562       if (y+h >= bmp->cb) {
1563 	 h = bmp->cb - y;
1564 	 if (h <= 0)
1565 	    return;
1566       }
1567 
1568       /* clip the left */
1569       if (x < bmp->cl) {
1570 	 d = bmp->cl - x;
1571 
1572 	 w -= d;
1573 	 if (w <= 0)
1574 	    return;
1575 
1576 	 data += d/8;
1577 	 lgap = d&7;
1578 	 x = bmp->cl;
1579       }
1580 
1581       /* clip the right */
1582       if (x+w >= bmp->cr) {
1583 	 w = bmp->cr - x;
1584 	 if (w <= 0)
1585 	    return;
1586       }
1587    }
1588 
1589    /* draw it */
1590    bmp_select(bmp);
1591 
1592    for (plane=0; plane < MIN(w, 4); plane++) {
1593       outportw(0x3C4, (0x100<<((x+plane)&3))|2);
1594       dat = data;
1595 
1596       for (j=0; j<h; j++) {
1597 	 addr = (unsigned long)bmp->line[y+j]+((x+plane)>>2);
1598 	 d = dat[(plane+lgap)/8];
1599 	 k = 0x80 >> ((plane+lgap)&7);
1600 	 i = plane;
1601 
1602 	 for (;;) {
1603 	    if (d & k)
1604 	       bmp_write8(addr, color);
1605 	    else if (bg >= 0)
1606 	       bmp_write8(addr, bg);
1607 
1608 	    i += 4;
1609 	    if (i >= w)
1610 	       break;
1611 
1612 	    k >>= 4;
1613 	    if (!k) {
1614 	       d = dat[(i+lgap)/8];
1615 	       k = 0x80 >> ((i+lgap)&7);
1616 	    }
1617 
1618 	    addr++;
1619 	 }
1620 
1621 	 dat += stride;
1622       }
1623    }
1624 }
1625 
1626 
1627 
1628 /* modex_fetch_mode_list:
1629  *  Creates a list of of currently implemented ModeX modes.
1630  */
modex_fetch_mode_list(void)1631 static GFX_MODE_LIST *modex_fetch_mode_list(void)
1632 {
1633    GFX_MODE_LIST *mode_list;
1634 
1635    mode_list = _AL_MALLOC(sizeof(GFX_MODE_LIST));
1636    if (!mode_list) return NULL;
1637 
1638    mode_list->mode = _AL_MALLOC(sizeof(modex_gfx_modes));
1639    if (!mode_list->mode) return NULL;
1640 
1641    memcpy(mode_list->mode, modex_gfx_modes, sizeof(modex_gfx_modes));
1642    mode_list->num_modes = sizeof(modex_gfx_modes) / sizeof(GFX_MODE) - 1;
1643 
1644    return mode_list;
1645 }
1646 
1647 
1648 
1649 /* really_split_modex_screen:
1650  *  Enables a horizontal split screen at the specified line.
1651  *  Based on code from Paul Fenwick's XLIBDJ, which was in turn based
1652  *  on Michael Abrash's routines in PC Techniques, June 1991.
1653  */
really_split_modex_screen(int line)1654 static void really_split_modex_screen(int line)
1655 {
1656    if (gfx_driver != &gfx_modex)
1657       return;
1658 
1659    if (line < 0)
1660       line = 0;
1661    else if (line >= SCREEN_H)
1662       line = 0;
1663 
1664    _screen_split_position = line;
1665 
1666    /* adjust the line for double-scanned modes */
1667    if (SCREEN_H <= 150)
1668       line <<= 2;
1669    else if (SCREEN_H <= 300)
1670       line <<= 1;
1671 
1672    /* disable panning of the split screen area */
1673    _alter_vga_register(0x3C0, 0x30, 0x20, 0x20);
1674 
1675    /* set the line compare registers */
1676    _write_vga_register(0x3D4, 0x18, (line-1) & 0xFF);
1677    _alter_vga_register(0x3D4, 7, 0x10, ((line-1) & 0x100) >> 4);
1678    _alter_vga_register(0x3D4, 9, 0x40, ((line-1) & 0x200) >> 3);
1679 }
1680 
1681 
1682 
1683 #endif      /* (!defined ALLEGRO_LINUX) || ((defined ALLEGRO_LINUX_VGA) && ... */
1684 
1685 
1686 #if (defined ALLEGRO_LINUX_VGA) && (defined ALLEGRO_MODULE)
1687 
1688 /* _module_init:
1689  *  Called when loaded as a dynamically linked module.
1690  */
_module_init_modex(int system_driver)1691 void _module_init_modex(int system_driver)
1692 {
1693    if (system_driver == SYSTEM_LINUX)
1694       _unix_register_gfx_driver(GFX_MODEX, &gfx_modex, TRUE, FALSE);
1695 }
1696 
1697 #endif	    /* (defined ALLEGRO_LINUX_VGA) && (defined ALLEGRO_MODULE) */
1698 
1699 
1700 #endif	    /* ALLEGRO_GFX_HAS_VGA */
1701