]> 4ch.mooo.com Git - 16.git/blob - 16/tweak16/XINTRO/lib.c
refresh wwww
[16.git] / 16 / tweak16 / XINTRO / lib.c
1 /*\r
2  * LIB.C v1.2a\r
3  *\r
4  * by Robert Schmidt\r
5  * (C)1993 Ztiff Zox Softwear\r
6  *\r
7  * Simple graphics library to accompany the article\r
8  * \r
9  *                      INTRODUCTION TO MODE X.\r
10  * \r
11  * This library provides the basic functions for initializing and using\r
12  * unchained (planar) 256-color VGA modes.  Currently supported are:\r
13  *\r
14  *      - 320x200\r
15  *      - 320x240\r
16  *\r
17  * Functions are provided for:\r
18  *\r
19  *      - initializing one of the available modes\r
20  *      - setting the start address of the VGA refresh data\r
21  *      - setting active and visible display pages\r
22  *      - writing and reading a single pixel to/from video memory\r
23  *\r
24  * The library is provided as a demonstration only, and is not claimed\r
25  * to be particularly efficient or suited for any purpose.  It has only\r
26  * been tested with Borland C++ 3.1 by the author.  Comments on success\r
27  * or disaster with other compilers are welcome.\r
28  *\r
29  * This file is public domain.  Do with it whatever you'd like, but\r
30  * please don't distribute it without the article.\r
31  *\r
32  * Thanks go out to various helpful netters who spotted the 0xE7 bug\r
33  * in the set320x240x256() function!\r
34  *\r
35  * modified by sparky4 so it can be compiled in open watcom ^^\r
36  */\r
37 \r
38 \r
39 /*\r
40  * We 'require' a large data model simply to get rid of explicit 'far'\r
41  * pointers and compiler specific '_fmemset()' functions and the likes.\r
42  */\r
43 \r
44 #if !defined(__COMPACT__)\r
45 # if !defined(__LARGE__)\r
46 #  if !defined(__HUGE__)\r
47 #   error Large data model required!  Try compiling with 'bcc -ml lib.c'.\r
48 #  endif\r
49 # endif\r
50 #endif\r
51 \r
52 #include <dos.h>\r
53 #include <mem.h>\r
54 #include <conio.h>\r
55 \r
56 /*\r
57  * Comment out the following #define if you don't want the testing main()\r
58  * to be included.\r
59  */\r
60 \r
61 #define TESTING\r
62 \r
63 /*\r
64  * Define the port addresses of some VGA registers.\r
65  */\r
66 \r
67 #define CRTC_ADDR       0x3d4   /* Base port of the CRT Controller (color) */\r
68 \r
69 #define SEQU_ADDR       0x3c4   /* Base port of the Sequencer */\r
70 #define GRAC_ADDR       0x3ce   /* Base port of the Graphics Controller */\r
71 \r
72 \r
73 /*\r
74  * Make a far pointer to the VGA graphics buffer segment.  Your compiler\r
75  * might not have the MK_FP macro, but you'll figure something out.\r
76  */\r
77 \r
78 typedef unsigned char UCHAR;\r
79 UCHAR *vga = (UCHAR *) MK_FP(0xA000, 0);\r
80 \r
81 /*\r
82  * width and height should specify the mode dimensions.  widthBytes\r
83  * specify the width of a line in addressable bytes.\r
84  */\r
85 \r
86 unsigned width, height, widthBytes;\r
87 \r
88 /*\r
89  * actStart specifies the start of the page being accessed by\r
90  * drawing operations.  visStart specifies the contents of the Screen\r
91  * Start register, i.e. the start of the visible page.\r
92  */\r
93 \r
94 unsigned actStart, visStart;\r
95 \r
96 /*\r
97  * set320x200x256_X()\r
98  *      sets mode 13h, then turns it into an unchained (planar), 4-page\r
99  *      320x200x256 mode.\r
100  */\r
101 \r
102 void set320x200x256_X(void)\r
103         {\r
104 \r
105         union REGS r;\r
106 \r
107         /* Set VGA BIOS mode 13h: */\r
108 \r
109         r.x.ax = 0x0013;\r
110         int86(0x10, &r, &r);\r
111 \r
112         /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */\r
113 \r
114         outpw(SEQU_ADDR, 0x0604);\r
115 \r
116         /* Turn off word mode, by setting the Mode Control register\r
117            of the CRT Controller (index 0x17, port 0x3d4): */\r
118 \r
119         outpw(CRTC_ADDR, 0xE317);\r
120 \r
121         /* Turn off doubleword mode, by setting the Underline Location\r
122            register (index 0x14, port 0x3d4): */\r
123 \r
124         outpw(CRTC_ADDR, 0x0014);\r
125 \r
126         /* Clear entire video memory, by selecting all four planes, then\r
127            writing 0 to entire segment. */\r
128 \r
129         outpw(SEQU_ADDR, 0x0F02);\r
130         memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */\r
131         vga[0] = 0;\r
132 \r
133         /* Update the global variables to reflect dimensions of this\r
134            mode.  This is needed by most future drawing operations. */\r
135 \r
136         width   = 320;\r
137         height  = 200;\r
138 \r
139         /* Each byte addresses four pixels, so the width of a scan line\r
140            in *bytes* is one fourth of the number of pixels on a line. */\r
141 \r
142         widthBytes = width / 4;\r
143 \r
144         /* By default we want screen refreshing and drawing operations\r
145        to be based at offset 0 in the video segment. */\r
146 \r
147         actStart = visStart = 0;\r
148 \r
149         }\r
150 \r
151 /*\r
152  * setActiveStart() tells our graphics operations which address in video\r
153  * memory should be considered the top left corner.\r
154  */\r
155 \r
156 void setActiveStart(unsigned offset)\r
157         {\r
158         actStart = offset;\r
159         }\r
160 \r
161 /*\r
162  * setVisibleStart() tells the VGA from which byte to fetch the first\r
163  * pixel when starting refresh at the top of the screen.  This version\r
164  * won't look very well in time critical situations (games for\r
165  * instance) as the register outputs are not synchronized with the\r
166  * screen refresh.  This refresh might start when the high byte is\r
167  * set, but before the low byte is set, which produces a bad flicker.\r
168  */\r
169 \r
170 void setVisibleStart(unsigned offset)\r
171         {\r
172         visStart = offset;\r
173         outpw(CRTC_ADDR, 0x0C);         /* set high byte */\r
174         outpw(CRTC_ADDR+1, visStart >> 8);\r
175         outpw(CRTC_ADDR, 0x0D);         /* set low byte */\r
176         outpw(CRTC_ADDR+1, visStart & 0xff);\r
177         }\r
178 \r
179 /*\r
180  * setXXXPage() sets the specified page by multiplying the page number\r
181  * with the size of one page at the current resolution, then handing the\r
182  * resulting offset value over to the corresponding setXXXStart()\r
183  * function.  The first page is number 0.\r
184  */\r
185 \r
186 void setActivePage(int page)\r
187         {\r
188         setActiveStart(page * widthBytes * height);\r
189         }\r
190 \r
191 void setVisiblePage(int page)\r
192         {\r
193         setVisibleStart(page * widthBytes * height);\r
194         }\r
195 \r
196 void putPixel_X(int x, int y, UCHAR color)\r
197         {\r
198 \r
199         /* Each address accesses four neighboring pixels, so set\r
200            Write Plane Enable according to which pixel we want\r
201            to modify.  The plane is determined by the two least\r
202            significant bits of the x-coordinate: */\r
203 \r
204         outp(0x3c4, 0x02);\r
205         outp(0x3c5, 0x01 << (x & 3));\r
206 \r
207         /* The offset of the pixel into the video segment is\r
208            offset = (width * y + x) / 4, and write the given\r
209            color to the plane we selected above.  Heed the active\r
210            page start selection. */\r
211 \r
212         vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;\r
213 \r
214         }\r
215 \r
216 UCHAR getPixel_X(int x, int y)\r
217         {\r
218 \r
219         /* Select the plane from which we must read the pixel color: */\r
220 \r
221         outpw(GRAC_ADDR, 0x04);\r
222         outpw(GRAC_ADDR+1, x & 3);\r
223 \r
224         return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];\r
225 \r
226         }\r
227 \r
228 void set320x240x256_X(void)\r
229         {\r
230 \r
231         /* Set the unchained version of mode 13h: */\r
232 \r
233         set320x200x256_X();\r
234 \r
235         /* Modify the vertical sync polarity bits in the Misc. Output\r
236            Register to achieve square aspect ratio: */\r
237 \r
238         outp(0x3C2, 0xE3);\r
239 \r
240         /* Modify the vertical timing registers to reflect the increased\r
241            vertical resolution, and to center the image as good as\r
242            possible: */\r
243 \r
244         outpw(0x3D4, 0x2C11);           /* turn off write protect */\r
245         outpw(0x3D4, 0x0D06);           /* vertical total */\r
246         outpw(0x3D4, 0x3E07);           /* overflow register */\r
247         outpw(0x3D4, 0xEA10);           /* vertical retrace start */\r
248         outpw(0x3D4, 0xAC11);           /* vertical retrace end AND wr.prot */\r
249         outpw(0x3D4, 0xDF12);           /* vertical display enable end */\r
250         outpw(0x3D4, 0xE715);           /* start vertical blanking */\r
251         outpw(0x3D4, 0x0616);           /* end vertical blanking */\r
252 \r
253         /* Update mode info, so future operations are aware of the\r
254            resolution */\r
255 \r
256         height = 240;\r
257 \r
258         }\r
259 \r
260 \r
261 \r
262 /*\r
263  * The library testing routines follows below.\r
264  */\r
265 \r
266 \r
267 #ifdef TESTING\r
268 \r
269 #include <stdio.h>\r
270 #include <conio.h>\r
271 \r
272 void set80x25(void)\r
273         {\r
274         union REGS r;\r
275         r.x.ax = 0x0003;\r
276         int86(0x10, &r, &r);\r
277         }\r
278 \r
279 void doTest(void)\r
280         {\r
281         int p, x, y, pages;\r
282 \r
283         /* This is the way to calculate the number of pages available. */\r
284 \r
285         pages = 65536L/(widthBytes*height);\r
286 \r
287         for (p = 0; p < pages; ++p)\r
288                 {\r
289                 setActivePage(p);\r
290 \r
291                 /* On each page draw a single colored border, and dump the palette\r
292                    onto a small square about the middle of the page. */\r
293 \r
294                 for (x = 0; x <= width; ++x)\r
295                         {\r
296                         putPixel_X(x, 0, p+1);\r
297                         putPixel_X(x, height-1, p+1);\r
298                         }\r
299 \r
300                 for (y = 0; y <= height; ++y)\r
301                         {\r
302                         putPixel_X(0, y, p+1);\r
303                         putPixel_X(width-1, y, p+1);\r
304                         }\r
305 \r
306                 for (x = 0; x < 16; ++x)\r
307                         for (y = 0; y < 16; ++y)\r
308                                 putPixel_X(x+(p+3)*16, y+(p+3)*16, x + y*16);\r
309 \r
310                 }\r
311 \r
312         /* Each pages will now contain a different image.  Let the user cycle\r
313            through all the pages by pressing a key. */\r
314 \r
315         for (p = 0; p < pages; ++p)\r
316                 {\r
317                 setVisiblePage(p);\r
318                 getch();\r
319                 }\r
320 \r
321         }\r
322 \r
323 \r
324 /*\r
325  * Library test (program) entry point.\r
326  */\r
327 \r
328 int main(void)\r
329         {\r
330 //      puts("First, have a look at the 320x200 mode.  I will draw some rubbish");\r
331 //      puts("on all of the four pages, then let you cycle through them by");\r
332 //      puts("hitting a key on each page.");\r
333 //      puts("Press a key when ready...");\r
334 //      getch();\r
335 \r
336 //      set320x200x256_X();\r
337 //      doTest();\r
338 \r
339 //      set80x25();\r
340 //      puts("Then, check out Mode X, 320x240 with 3 (and a half) pages.");\r
341 //      puts("Press a key when ready...");\r
342 //      getch();\r
343 \r
344         set320x240x256_X();\r
345         doTest();\r
346 \r
347         set80x25();\r
348         puts("Where to next?  It's your move!");\r
349         return 0;\r
350         }\r
351 \r
352 #endif\r