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