]> 4ch.mooo.com Git - 16.git/blob - 16/grdemo.c
more
[16.git] / 16 / grdemo.c
1 /*****************************************************************************\r
2 VGA graphics demo\r
3 Chris Giese <geezer@execpc.com> http://my.execpc.com/~geezer\r
4 Release date: ?\r
5 This code is public domain (no copyright).\r
6 You can do whatever you want with it.\r
7 \r
8 This code uses the BIOS to set graphics mode, and uses the BIOS font.\r
9 Should compile cleanly with Turbo C++ 1.0, Turbo C++ 3.0, 16- or 32-bit\r
10 Watcom C, or DJGPP. DJGPP version will not work in Windows NT/2000/XP\r
11 DOS box.\r
12 \r
13 Some additional things you could do with this:\r
14 - Write a function tblit1(), similar to blit1(), that uses an on-off\r
15   transparency mask. Use this function to blit non-rectangular objects\r
16   such as a mouse cursor.\r
17 - Write blit_plane(): a fast function to blit from monochrome to monochrome\r
18   or 4-plane bitmaps. Use an external shift() function, written in asm\r
19 - Support VBE 1.x banked framebuffer\r
20 - Support VBE 2.x linear framebuffer (pmode only, not at A000h:0000)\r
21 - Support greater color depths: 15 bpp, 16 bpp, 24 bpp, 32 bpp\r
22 - Color reduction, e.g. Heckbert (median-cut) algorithm\r
23 - Clipping engine that lets you draw a window that is partially\r
24   obscured by "closer" windows\r
25 - Mouse, keyboard, and timer events\r
26 - Widgets: push button, checkbox, radio buttons, listbox, dialog, etc.\r
27 *****************************************************************************/\r
28 #include <string.h> /* [_f]memset() */\r
29 /********************************* TURBO C **********************************/\r
30 #if defined(__TURBOC__)\r
31 #include <dos.h> /* struct REGPACK, intr() */\r
32 \r
33 /* The framebuffer is far outside the 16-bit data segment. The only way to\r
34 make the framebuffer work like in-memory bitmaps is to use far pointers.\r
35 \r
36 We still use the SMALL memory model. */\r
37 #define FAR             far\r
38 #define FARPTR(S, O)    MK_FP(S, O)\r
39 \r
40 #define outportw(P,V)   outport(P,V)\r
41 \r
42 #define R_AX            r_ax\r
43 #define R_BX            r_bx\r
44 #define R_BP            r_bp\r
45 #define R_ES            r_es\r
46 \r
47 #define trap(N,R)       intr(N,R)\r
48 \r
49 typedef struct REGPACK regs_t;\r
50 \r
51 #if __TURBOC__<0x300\r
52 void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
53 {\r
54         for(; n != 0; n--)\r
55         {\r
56                 *s = c;\r
57                 s++;\r
58         }\r
59 }\r
60 #else\r
61 void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
62 {\r
63         _fmemset(s, c, n);\r
64 }\r
65 #endif\r
66 \r
67 /********************************* DJGPP ************************************/\r
68 #elif defined(__DJGPP__)\r
69 #include <dpmi.h> /* __dpmi_... */\r
70 #include <dos.h> /* inportb(), outportb() */\r
71 \r
72 #define FAR             /* nothing */\r
73 #define FARPTR(S, O)    (unsigned char *)((S) * 16L + (O) + \\r
74                                 __djgpp_conventional_base)\r
75 \r
76 /* near pointers; not supported in Windows NT/2k/XP DOS box */\r
77 #include <sys/nearptr.h> /* __djgpp_conventional_base, __djgpp_nearptr_enable() */\r
78 #include <stdio.h> /* printf() */\r
79 #include <crt0.h> /* _CRT0_FLAG_NEARPTR, _crt0_startup_flags */\r
80 \r
81 #define R_AX            x.ax\r
82 #define R_BX            x.bx\r
83 #define R_BP            x.bp\r
84 #define R_ES            x.es\r
85 \r
86 #define trap(N,R)       __dpmi_int(N,R)\r
87 \r
88 typedef __dpmi_regs     regs_t;\r
89 \r
90 void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
91 {\r
92         memset(s, c, n);\r
93 }\r
94 \r
95 /******************************** WATCOM C **********************************/\r
96 #elif defined(__WATCOMC__)\r
97 #include <dos.h> /* union REGPACK, MK_FP(), intr() */\r
98 \r
99 #if defined(__386__)\r
100 #define FAR             /* nothing */\r
101 #define FARPTR(S, O)    (unsigned char *)((S) * 16L + (O))\r
102 \r
103 void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
104 {\r
105         memset(s, c, n);\r
106 }\r
107 \r
108 #else\r
109 #define FAR             far\r
110 #define FARPTR(S, O)    MK_FP(S, O)\r
111 \r
112 void vmemset(unsigned char FAR *s, unsigned c, unsigned n)\r
113 {\r
114         _fmemset(s, c, n);\r
115 }\r
116 #endif\r
117 \r
118 #define inportb(P)      inp(P)\r
119 #define outportb(P,V)   outp(P,V)\r
120 #define outportw(P,V)   outpw(P,V)\r
121 \r
122 #define R_AX            w.ax\r
123 #define R_BX            w.bx\r
124 #define R_BP            w.bp\r
125 #define R_ES            w.es\r
126 \r
127 /* WARNING: for 32-bit code, unused fields of regs_t\r
128 must be zeroed before using this macro */\r
129 #define trap(N,R)       intr(N,R)\r
130 \r
131 typedef union REGPACK   regs_t;\r
132 \r
133 #else\r
134 #error Not Turbo C, not DJGPP, not Watcom C. Sorry.\r
135 #endif\r
136 \r
137 #include <conio.h> /* getch() */\r
138 \r
139 /* need direct access to some VGA registers to select plane,\r
140 enable Mode X, and fix screwy CGA addressing */\r
141 #define VGA_SEQ_INDEX           0x3C4\r
142 #define VGA_SEQ_DATA            0x3C5\r
143 #define VGA_GC_INDEX            0x3CE\r
144 #define VGA_GC_DATA             0x3CF\r
145 #define VGA_CRTC_INDEX          0x3D4\r
146 #define VGA_CRTC_DATA           0x3D5\r
147 \r
148 /* bitmap "class" */\r
149 typedef struct\r
150 {\r
151         unsigned wd, ht;\r
152         unsigned char FAR *raster;\r
153         unsigned fore_color, back_color;\r
154 /* "member functions" */\r
155         const struct _driver *ops;\r
156 } bmp_t;\r
157 \r
158 typedef struct _driver\r
159 {\r
160 /* "pure virtual functions": color drivers MUST implement these */\r
161         void (*write_pixel)(bmp_t *bmp, unsigned x, unsigned y, unsigned c);\r
162         unsigned (*read_pixel)(bmp_t *bmp, unsigned x, unsigned y);\r
163 /* "virtual functions": drivers MAY implement these, for speed\r
164 fill rectangular area with solid color */\r
165         void (*fill_rect)(bmp_t *bmp, int x, int y, int wd, int ht);\r
166 /* copy monochrome bitmap to this bitmap (used to display text) */\r
167         void (*blit1)(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y);\r
168 /* copy all or part of one bitmap to another (both of the same depth) */\r
169         void (*blit)(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y);\r
170 } ops_t;\r
171 /*============================================================================\r
172 helper functions\r
173 ============================================================================*/\r
174 /*****************************************************************************\r
175 *****************************************************************************/\r
176 void set_plane(unsigned p)\r
177 {\r
178         static unsigned curr_p = -1u;\r
179 /**/\r
180         unsigned char pmask;\r
181 \r
182         p &= 3;\r
183         if(p == curr_p)\r
184                 return;\r
185         curr_p = p;\r
186         pmask = 1 << p;\r
187 #if 0\r
188         outportb(VGA_GC_INDEX, 4);\r
189         outportb(VGA_GC_DATA, p);\r
190         outportb(VGA_SEQ_INDEX, 2);\r
191         outportb(VGA_SEQ_DATA, pmask);\r
192 #else\r
193 /* this is a little faster... */\r
194         outportw(VGA_GC_INDEX, (p << 8) | 4);\r
195         outportw(VGA_SEQ_INDEX, (pmask << 8) | 2);\r
196 #endif\r
197 }\r
198 /*****************************************************************************\r
199 fast planar (monochrome or 16-color) rectangle fill\r
200 *****************************************************************************/\r
201 void fill_plane(bmp_t *bmp, int x, int y, int wd, int ht, unsigned c)\r
202 {\r
203         unsigned w, wd_in_bytes, off;\r
204         unsigned char lmask, rmask;\r
205         int x2, y2;\r
206 \r
207         x2 = x + wd - 1;\r
208         w = (x2 >> 3) - (x >> 3) + 1;\r
209         lmask = 0x00FF >> (x & 7); /* FF 7F 3F 1F 0F 07 03 01 */\r
210         rmask = 0xFF80 >> (x2 & 7);/* 80 C0 E0 F0 F8 FC FE FF */\r
211         if(w == 1)\r
212                 lmask &= rmask;\r
213         wd_in_bytes = bmp->wd / 8;\r
214         off = wd_in_bytes * y + x / 8;\r
215         if(c)\r
216 /* for each row... */\r
217                 for(y2 = y; y2 < y + ht; y2++)\r
218                 {\r
219 /* do partial byte on left */\r
220                         bmp->raster[off] |= lmask;\r
221 /* do solid bytes in middle */\r
222                         if(w > 2)\r
223                                 vmemset(bmp->raster + off + 1, 0xFF, w - 2);\r
224 /* do partial byte on right */\r
225                         if(w > 1)\r
226                                 bmp->raster[off + w - 1] |= rmask;\r
227 /* next row */\r
228                         off += wd_in_bytes;\r
229                 }\r
230         else\r
231         {\r
232                 lmask = ~lmask;\r
233                 rmask = ~rmask;\r
234                 for(y2 = y; y2 < y + ht; y2++)\r
235                 {\r
236                         bmp->raster[off] &= lmask;\r
237                         if(w > 2)\r
238                                 vmemset(bmp->raster + off + 1, 0, w - 2);\r
239                         if(w > 1)\r
240                                 bmp->raster[off + w - 1] &= rmask;\r
241                         off += wd_in_bytes;\r
242                 }\r
243         }\r
244 }\r
245 /*****************************************************************************\r
246 fast planar blit\r
247 *****************************************************************************/\r
248 void blit_plane(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
249 {\r
250 /* left as an exercise for the reader :)\r
251 \r
252 You may need an external, assembly-language function to shift (left or\r
253 right) a long string of bytes. No need to shift by more than 7 bits. */\r
254 }\r
255 /*============================================================================\r
256 driver for monochrome (1-bit) graphics\r
257 ============================================================================*/\r
258 /*****************************************************************************\r
259 *****************************************************************************/\r
260 static void write_pixel1(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
261 {\r
262         unsigned wd_in_bytes;\r
263         unsigned off, mask;\r
264 \r
265         c = (c & 1) * 0xFF;\r
266         wd_in_bytes = bmp->wd / 8;\r
267         off = wd_in_bytes * y + x / 8;\r
268         x = (x & 7) * 1;\r
269         mask = 0x80 >> x;\r
270         bmp->raster[off] = (bmp->raster[off] & ~mask) | (c & mask);\r
271 }\r
272 /*****************************************************************************\r
273 *****************************************************************************/\r
274 static unsigned read_pixel1(bmp_t *bmp, unsigned x, unsigned y)\r
275 {\r
276         unsigned wd_in_bytes;\r
277         unsigned off, mask;\r
278 \r
279         wd_in_bytes = bmp->wd / 8;\r
280         off = wd_in_bytes * y + x / 8;\r
281         x = (x & 7) * 1;\r
282         mask = 0x80 >> x;\r
283         return (bmp->raster[off] & mask) != 0;\r
284 }\r
285 /*****************************************************************************\r
286 *****************************************************************************/\r
287 static void fill_rect1(bmp_t *bmp, int x, int y, int wd, int ht)\r
288 {\r
289         fill_plane(bmp, x, y, wd, ht, bmp->fore_color & 1);\r
290 }\r
291 /*****************************************************************************\r
292 *****************************************************************************/\r
293 const ops_t g_ops1 =\r
294 {\r
295         write_pixel1,\r
296         read_pixel1,\r
297         fill_rect1,\r
298         NULL, /* blit1 */\r
299         NULL /* blit */\r
300 };\r
301 /*============================================================================\r
302 driver for 2-bit packed pixel (4-color CGA) graphics\r
303 ============================================================================*/\r
304 /*****************************************************************************\r
305 *****************************************************************************/\r
306 static void write_pixel2(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
307 {\r
308         unsigned wd_in_bytes, off, mask;\r
309 \r
310         c = (c & 3) * 0x55;\r
311         wd_in_bytes = bmp->wd / 4;\r
312         off = wd_in_bytes * y + x / 4;\r
313         x = (x & 3) * 2;\r
314         mask = 0xC0 >> x;\r
315         bmp->raster[off] = (bmp->raster[off] & ~mask) | (c & mask);\r
316 }\r
317 /*****************************************************************************\r
318 *****************************************************************************/\r
319 const ops_t g_ops2 =\r
320 {\r
321         write_pixel2,\r
322         NULL, /* read_pixel */\r
323         NULL, /* fill_rect */\r
324         NULL, /* blit1 */\r
325         NULL /* blit */\r
326 };\r
327 /*============================================================================\r
328 driver for 4-plane 16-color graphics\r
329 ============================================================================*/\r
330 /*****************************************************************************\r
331 *****************************************************************************/\r
332 static void write_pixel4p(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
333 {\r
334         unsigned wd_in_bytes, off, mask, p, pmask;\r
335 \r
336         wd_in_bytes = bmp->wd / 8;\r
337         off = wd_in_bytes * y + x / 8;\r
338         x = (x & 7) * 1;\r
339         mask = 0x80 >> x;\r
340         pmask = 1;\r
341         for(p = 0; p < 4; p++)\r
342         {\r
343                 set_plane(p);\r
344                 if(pmask & c)\r
345                         bmp->raster[off] |= mask;\r
346                 else\r
347                         bmp->raster[off] &= ~mask;\r
348                 pmask <<= 1;\r
349         }\r
350 }\r
351 /*****************************************************************************\r
352 pixel-by-pixel fill is too slow, so use this optimized function:\r
353 *****************************************************************************/\r
354 static void fill_rect4p(bmp_t *bmp, int x, int y, int wd, int ht)\r
355 {\r
356         unsigned char p, pmask;\r
357 \r
358         pmask = 1;\r
359         for(p = 0; p < 4; p++)\r
360         {\r
361                 set_plane(p);\r
362                 fill_plane(bmp, x, y, wd, ht, bmp->fore_color & pmask);\r
363                 pmask <<= 1;\r
364         }\r
365 }\r
366 /*****************************************************************************\r
367 *****************************************************************************/\r
368 const ops_t g_ops4p =\r
369 {\r
370         write_pixel4p,\r
371         NULL, /* read_pixel */\r
372         fill_rect4p,\r
373         NULL, /* blit1 */\r
374         NULL /* blit */\r
375 };\r
376 /*============================================================================\r
377 driver for 8-bit 256-color graphics\r
378 ============================================================================*/\r
379 /*****************************************************************************\r
380 *****************************************************************************/\r
381 static void write_pixel8(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
382 {\r
383         unsigned wd_in_bytes;\r
384         unsigned off;\r
385 \r
386         wd_in_bytes = bmp->wd;\r
387         off = wd_in_bytes * y + x;\r
388         bmp->raster[off] = c;\r
389 }\r
390 /*****************************************************************************\r
391 *****************************************************************************/\r
392 static void fill_rect8(bmp_t *bmp, int x, int y, int wd, int ht)\r
393 {\r
394         unsigned wd_in_bytes, off, y2;\r
395 \r
396         wd_in_bytes = bmp->wd;\r
397         off = wd_in_bytes * y + x;\r
398         for(y2 = y; y2 < y + ht; y2++)\r
399         {\r
400                 vmemset(bmp->raster + off, bmp->fore_color, wd);\r
401                 off += wd_in_bytes;\r
402         }\r
403 }\r
404 /*****************************************************************************\r
405 *****************************************************************************/\r
406 const ops_t g_ops8 =\r
407 {\r
408         write_pixel8,\r
409         NULL, /* read_pixel */\r
410         fill_rect8,\r
411         NULL, /* blit1 */\r
412         NULL /* blit */\r
413 };\r
414 /*============================================================================\r
415 driver for 8-bit 256-color Mode-X graphics\r
416 ============================================================================*/\r
417 /*****************************************************************************\r
418 *****************************************************************************/\r
419 static void write_pixel8x(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
420 {\r
421         unsigned wd_in_bytes;\r
422         unsigned off;\r
423 \r
424         wd_in_bytes = bmp->wd / 4;\r
425         off = wd_in_bytes * y + x / 4;\r
426         set_plane(x & 3);\r
427         bmp->raster[off] = c;\r
428 }\r
429 /*****************************************************************************\r
430 *****************************************************************************/\r
431 const ops_t g_ops8x =\r
432 {\r
433         write_pixel8x,\r
434         NULL, /* read_pixel */\r
435         NULL, /* fill_rect */\r
436         NULL, /* blit1 */\r
437         NULL /* blit */\r
438 };\r
439 /*============================================================================\r
440 depth-independent routines, which call the depth-dependent routines\r
441 ============================================================================*/\r
442 /*****************************************************************************\r
443 *****************************************************************************/\r
444 unsigned read_pixel(bmp_t *bmp, unsigned x, unsigned y)\r
445 {\r
446         if(x >= bmp->wd || y >= bmp->ht)\r
447                 return 0;\r
448         if(bmp->ops->read_pixel == NULL)\r
449                 return 0; /* uh-oh */\r
450         return bmp->ops->read_pixel(bmp, x, y);\r
451 }\r
452 /*****************************************************************************\r
453 *****************************************************************************/\r
454 void write_pixel(bmp_t *bmp, unsigned x, unsigned y, unsigned c)\r
455 {\r
456         if(x >= bmp->wd || y >= bmp->ht)\r
457                 return;\r
458         if(bmp->ops->write_pixel == NULL)\r
459                 return; /* uh-oh */\r
460         bmp->ops->write_pixel(bmp, x, y, c);\r
461 }\r
462 /*****************************************************************************\r
463 *****************************************************************************/\r
464 void fill_rect(bmp_t *bmp, int x, int y, int wd, int ht)\r
465 {\r
466         int x2, y2;\r
467 \r
468 /* clip */\r
469         if(x < 0)\r
470         {\r
471                 if(wd + x < 0)\r
472                         return;\r
473                 wd += x;\r
474                 x = 0;\r
475         }\r
476         if(x + wd >= (int)bmp->wd)\r
477         {\r
478                 if(x >= (int)bmp->wd)\r
479                         return;\r
480                 wd = bmp->wd - x;\r
481         }\r
482         if(y < 0)\r
483         {\r
484                 if(ht + y < 0)\r
485                         return;\r
486                 ht += y;\r
487                 y = 0;\r
488         }\r
489         if(y + ht >= (int)bmp->ht)\r
490         {\r
491                 if(y >= (int)bmp->ht)\r
492                         return;\r
493                 ht = bmp->ht - y;\r
494         }\r
495 /* use fast routine if available */\r
496         if(bmp->ops->fill_rect != NULL)\r
497         {\r
498                 bmp->ops->fill_rect(bmp, x, y, wd, ht);\r
499                 return;\r
500         }\r
501         for(y2 = y; y2 < y + ht; y2++)\r
502                 for(x2 = x; x2 < x + wd; x2++)\r
503                         write_pixel(bmp, x2, y2, bmp->fore_color);\r
504 }\r
505 /*****************************************************************************\r
506 *****************************************************************************/\r
507 void hline(bmp_t *bmp, int x, int y, unsigned wd)\r
508 {\r
509         fill_rect(bmp, x, y, wd, 1);\r
510 }\r
511 /*****************************************************************************\r
512 *****************************************************************************/\r
513 void vline(bmp_t *bmp, int x, int y, unsigned ht)\r
514 {\r
515         fill_rect(bmp, x, y, 1, ht);\r
516 }\r
517 /*****************************************************************************\r
518 blit1 = blit from monochrome bitmap to bitmap of any color depth\r
519 *****************************************************************************/\r
520 void blit1(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
521 {\r
522         unsigned x, y, c;\r
523 \r
524 /* source bitmap _must_ be monochrome */\r
525         if(src->ops != &g_ops1)\r
526                 return;\r
527 /* use fast routine if available */\r
528         if(src->ops->blit1 != NULL)\r
529         {\r
530                 src->ops->blit1(src, dst, dst_x, dst_y);\r
531                 return;\r
532         }\r
533         for(y = 0; y < src->ht; y++)\r
534                 for(x = 0; x < src->wd; x++)\r
535                 {\r
536                         c = read_pixel(src, x, y);\r
537 /* xxx - on-off transparency?\r
538                         if(c == 0)\r
539                                 continue; */\r
540                         if(c != 0)\r
541                                 c = dst->fore_color;\r
542                         else\r
543                                 c = dst->back_color;\r
544                         write_pixel(dst, dst_x + x, dst_y + y, c);\r
545                 }\r
546 }\r
547 /*****************************************************************************\r
548 blit = copy from one bitmap to another, both of the same color depth\r
549 *****************************************************************************/\r
550 void blit(bmp_t *src, bmp_t *dst, unsigned dst_x, unsigned dst_y)\r
551 {\r
552         unsigned x, y, c;\r
553 \r
554 /* they must be the same depth */\r
555         if(src->ops != dst->ops)\r
556                 return;\r
557 /* use fast routine if available */\r
558         if(src->ops->blit != NULL)\r
559         {\r
560                 src->ops->blit(src, dst, dst_x, dst_y);\r
561                 return;\r
562         }\r
563         for(y = 0; y < src->ht; y++)\r
564                 for(x = 0; x < src->wd; x++)\r
565                 {\r
566                         c = read_pixel(src, x, y);\r
567                         write_pixel(dst, dst_x + x, dst_y + y, c);\r
568                 }\r
569 }\r
570 /*****************************************************************************\r
571 find 8x8 font in VGA BIOS ROM\r
572 *****************************************************************************/\r
573 unsigned char FAR *bios_8x8_font(void)\r
574 {\r
575         unsigned char FAR *font;\r
576         regs_t regs;\r
577 \r
578 /* use BIOS INT 10h AX=1130h to find font #3 (8x8) in ROM */\r
579         memset(&regs, 0, sizeof(regs)); /* for Watcom C */\r
580         regs.R_AX = 0x1130;\r
581         regs.R_BX = 0x0300;\r
582         trap(0x10, &regs);\r
583 /* CauseWay DOS extender seems to return a selector in ES,\r
584 instead of real-mode segment value (usu. 0xC000) */\r
585 #if defined(__WATCOMC__)&&defined(__386__)\r
586         font = FARPTR(0xC000, regs.R_BP);\r
587 #else\r
588         font = FARPTR(regs.R_ES, regs.R_BP);\r
589 #endif\r
590         return font;\r
591 }\r
592 /*****************************************************************************\r
593 *****************************************************************************/\r
594 void bputs(bmp_t *bmp, unsigned x, unsigned y, const char *s)\r
595 {\r
596         unsigned char FAR *font;\r
597         bmp_t src;\r
598 \r
599         font = bios_8x8_font();\r
600         src.wd = 8;\r
601         src.ht = 8;\r
602         src.ops = &g_ops1;\r
603         for(; *s != '\0'; s++)\r
604         {\r
605                 src.raster = font + 8 * (*s);\r
606                 blit1(&src, bmp, x, y);\r
607                 x += 8;\r
608         }\r
609 }\r
610 /*============================================================================\r
611 DEMO\r
612 ============================================================================*/\r
613 /*****************************************************************************\r
614 *****************************************************************************/\r
615 static void border3d(bmp_t *bmp, int x, int y, unsigned wd, unsigned ht,\r
616                 char down)\r
617 {\r
618         if(down)\r
619         {\r
620                 bmp->fore_color = 8;\r
621                 hline(bmp, x + 0, y + 0, wd - 1);\r
622                 vline(bmp, x + 0, y + 0, ht - 1);\r
623                 bmp->fore_color = 0;\r
624                 hline(bmp, x + 1, y + 1, wd - 3);\r
625                 vline(bmp, x + 1, y + 1, ht - 3);\r
626                 bmp->fore_color = 7;\r
627                 hline(bmp, x + 1, y + ht - 2, wd - 2);\r
628                 vline(bmp, x + wd - 2, y + 1, ht - 2);\r
629                 bmp->fore_color = 15;\r
630                 hline(bmp, x + 0, y + ht - 1, wd);\r
631                 vline(bmp, x + wd - 1, y + 0, ht);\r
632         }\r
633         else\r
634         {\r
635                 bmp->fore_color = 7;\r
636                 hline(bmp, x + 0, y + 0, wd - 1);\r
637                 vline(bmp, x + 0, y + 0, ht - 1);\r
638                 bmp->fore_color = 15;\r
639                 hline(bmp, x + 1, y + 1, wd - 3);\r
640                 vline(bmp, x + 1, y + 1, ht - 3);\r
641                 bmp->fore_color = 8;\r
642                 hline(bmp, x + 1, y + ht - 2, wd - 2);\r
643                 vline(bmp, x + wd - 2, y + 1, ht - 2);\r
644                 bmp->fore_color = 0;\r
645                 hline(bmp, x + 0, y + ht - 1, wd);\r
646                 vline(bmp, x + wd - 1, y + 0, ht);\r
647         }\r
648 }\r
649 /*****************************************************************************\r
650 *****************************************************************************/\r
651 static void demo(bmp_t *bmp, const char *title)\r
652 {\r
653         unsigned x = 10, y = 10, wd = 180, ht = 50;\r
654 \r
655 /* erase screen to blue */\r
656         bmp->fore_color = 1;\r
657         fill_rect(bmp, 0, 0, bmp->wd, bmp->ht);\r
658 /* draw gray window with 3D border */\r
659         bmp->fore_color = 7;\r
660         fill_rect(bmp, x, y, wd, ht);\r
661         border3d(bmp, x, y, wd, ht, 0);\r
662 /* draw white-on-green title bar */\r
663         bmp->fore_color = 2;\r
664         fill_rect(bmp, x + 2, y + 2, wd - 4, 10);\r
665         bmp->back_color = 2;\r
666         bmp->fore_color = 15;\r
667         bputs(bmp, x + 3, y + 3, title);\r
668 /* draw menu bar on existing gray background */\r
669         bmp->back_color = 7;\r
670         bmp->fore_color = 0;\r
671         bputs(bmp, x + 3, y + 13, "File Edit");\r
672 /* draw white inner area with 3D border */\r
673         bmp->fore_color = 15;\r
674         fill_rect(bmp, x + 3, y + 21, wd - 6, ht - 24);\r
675         border3d(bmp, x + 3, y + 21, wd - 6, ht - 24, 1);\r
676 /* await key pressed */\r
677         getch();\r
678 }\r
679 /*****************************************************************************\r
680 *****************************************************************************/\r
681 int main(void)\r
682 {\r
683         static const unsigned wd[] =\r
684         {\r
685                 640, 320, 640, 320, 320\r
686         };\r
687         static const unsigned ht[] =\r
688         {\r
689                 480, 200, 480, 200, 200\r
690         };\r
691         static const ops_t *ops[] =\r
692         {\r
693                 &g_ops1, &g_ops2, &g_ops4p, &g_ops8, &g_ops8x\r
694         };\r
695         static const unsigned mode[] =\r
696         {\r
697                 0x11, 5, 0x12, 0x13, 0x13\r
698         };\r
699         static const char *title[] =\r
700         {\r
701                 "640x480x2", "320x200x4", "640x480x16", "320x200x256",\r
702                         "320x200x256 ModeX"\r
703         };\r
704 /**/\r
705         regs_t regs;\r
706         unsigned i;\r
707         bmp_t bmp;\r
708 \r
709 #if defined(__DJGPP__)\r
710         if(!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR))\r
711         {\r
712                 if(!__djgpp_nearptr_enable())\r
713                 {\r
714                         printf("Could not enable nearptr access "\r
715                                 "(Windows NT/2000/XP?)\n");\r
716                 }\r
717         }\r
718 #endif\r
719         for(i = 0; i < sizeof(wd) / sizeof(wd[0]); i++)\r
720         {\r
721                 bmp.raster = FARPTR(0xA000, 0);\r
722                 bmp.wd = wd[i];\r
723                 bmp.ht = ht[i];\r
724                 bmp.ops = ops[i];\r
725 \r
726                 memset(&regs, 0, sizeof(regs)); /* for Watcom C */\r
727                 regs.R_AX = mode[i];\r
728                 trap(0x10, &regs);\r
729 /* to make CGA graphics work like other graphics modes... */\r
730                 if(mode[i] == 0x05)\r
731                 {\r
732 /* 1) turn off screwy CGA addressing */\r
733                         outportb(VGA_CRTC_INDEX, 0x17);\r
734                         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) | 1);\r
735 /* 2) turn off doublescan */\r
736                         outportb(VGA_CRTC_INDEX, 9);\r
737                         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x80);\r
738 /* 3) move the framebuffer from B800:0000 to A000:0000 */\r
739                         outportb(VGA_GC_INDEX, 6);\r
740                         outportb(VGA_GC_DATA, inportb(VGA_GC_INDEX) & ~0x0C);\r
741                 }\r
742 /* to convert mode 13h to Mode X... */\r
743                 else if(i == 4)\r
744                 {\r
745 /* 1) turn off Chain-4 addressing */\r
746                         outportb(VGA_SEQ_INDEX, 0x04);\r
747                         outportb(VGA_SEQ_DATA, inportb(VGA_SEQ_DATA) & ~0x08);\r
748 /* 2) turn off doubleword clocking */\r
749                         outportb(VGA_CRTC_INDEX, 0x14);\r
750                         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) & ~0x40);\r
751 /* 3) turn off word clocking in case it's on */\r
752                         outportb(VGA_CRTC_INDEX, 0x17);\r
753                         outportb(VGA_CRTC_DATA, inportb(VGA_CRTC_DATA) | 0x40);\r
754                 }\r
755                 demo(&bmp, title[i]);\r
756         }\r
757 /* return to text mode */\r
758         memset(&regs, 0, sizeof(regs)); /* for Watcom C */\r
759         regs.R_AX = 0x03;\r
760         trap(0x10, &regs);\r
761         return 0;\r
762 }\r