5 * (C)1993 Ztiff Zox Softwear
\r
7 * Simple graphics library to accompany the article
\r
9 * INTRODUCTION TO MODE X.
\r
11 * This library provides the basic functions for initializing and using
\r
12 * unchained (planar) 256-color VGA modes. Currently supported are:
\r
17 * Functions are provided for:
\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
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
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
32 * Thanks go out to various helpful netters who spotted the 0xE7 bug
\r
33 * in the set320x240x256() function!
\r
35 * modified by sparky4 so it can be compiled in open watcom ^^
\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
43 #if !defined(__COMPACT__)
\r
44 # if !defined(__LARGE__)
\r
45 # if !defined(__HUGE__)
\r
46 # error Large data model required! Try compiling with 'bcc -ml lib.c'.
\r
55 //code from old library!
\r
57 #include "dos_gfx.h"
\r
60 //color
\82Ä
\82·
\82Æ
\r
64 int bakax = 0, bakay = 0;
\r
65 int xx = rand()&0%320, yy = rand()&0%240, sx = 0, sy = 0;
\r
69 * Comment out the following #define if you don't want the testing main()
\r
75 * Define the port addresses of some VGA registers.
\r
77 #define CRTC_ADDR 0x3d4 /* Base port of the CRT Controller (color) */
\r
79 #define SEQU_ADDR 0x3c4 /* Base port of the Sequencer */
\r
80 #define GRAC_ADDR 0x3ce /* Base port of the Graphics Controller */
\r
84 * Make a far pointer to the VGA graphics buffer segment. Your compiler
\r
85 * might not have the MK_FP macro, but you'll figure something out.
\r
87 byte *vga = (byte *) MK_FP(0xA000, 0);
\r
89 //fontAddr = getFont();
\r
92 * width and height should specify the mode dimensions. widthBytes
\r
93 * specify the width of a line in addressable bytes.
\r
95 unsigned width, height, widthBytes;
\r
98 * actStart specifies the start of the page being accessed by
\r
99 * drawing operations. visStart specifies the contents of the Screen
\r
100 * Start register, i.e. the start of the visible page.
\r
102 unsigned actStart, visStart;
\r
105 * set320x200x256_X()
\r
106 * sets mode 13h, then turns it into an unchained (planar), 4-page
\r
107 * 320x200x256 mode.
\r
109 void set320x200x256_X(void)
\r
113 /* Set VGA BIOS mode 13h: */
\r
115 int86(0x10, &r, &r);
\r
117 /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */
\r
118 outpw(SEQU_ADDR, 0x0604);
\r
120 /* Turn off word mode, by setting the Mode Control register
\r
121 of the CRT Controller (index 0x17, port 0x3d4): */
\r
122 outpw(CRTC_ADDR, 0xE317);
\r
124 /* Turn off doubleword mode, by setting the Underline Location
\r
125 register (index 0x14, port 0x3d4): */
\r
126 outpw(CRTC_ADDR, 0x0014);
\r
128 /* Clear entire video memory, by selecting all four planes, then
\r
129 writing 0 to entire segment. */
\r
130 outpw(SEQU_ADDR, 0x0F02);
\r
131 memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */
\r
134 /* Update the global variables to reflect dimensions of this
\r
135 mode. This is needed by most future drawing operations. */
\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 widthBytes = width / 4;
\r
143 /* By default we want screen refreshing and drawing operations
\r
144 to be based at offset 0 in the video segment. */
\r
145 actStart = visStart = 0;
\r
149 * setActiveStart() tells our graphics operations which address in video
\r
150 * memory should be considered the top left corner.
\r
152 void setActiveStart(unsigned offset)
\r
158 * setVisibleStart() tells the VGA from which byte to fetch the first
\r
159 * pixel when starting refresh at the top of the screen. This version
\r
160 * won't look very well in time critical situations (games for
\r
161 * instance) as the register outputs are not synchronized with the
\r
162 * screen refresh. This refresh might start when the high byte is
\r
163 * set, but before the low byte is set, which produces a bad flicker.
\r
165 void setVisibleStart(unsigned offset)
\r
168 outpw(CRTC_ADDR, 0x0C); /* set high byte */
\r
169 outpw(CRTC_ADDR+1, visStart >> 8);
\r
170 outpw(CRTC_ADDR, 0x0D); /* set low byte */
\r
171 outpw(CRTC_ADDR+1, visStart & 0xff);
\r
175 * setXXXPage() sets the specified page by multiplying the page number
\r
176 * with the size of one page at the current resolution, then handing the
\r
177 * resulting offset value over to the corresponding setXXXStart()
\r
178 * function. The first page is number 0.
\r
180 void setActivePage(int page)
\r
182 setActiveStart(page * widthBytes * height);
\r
185 void setVisiblePage(int page)
\r
187 setVisibleStart(page * widthBytes * height);
\r
190 void putPixel_X(int x, int y, byte color)
\r
192 /* Each address accesses four neighboring pixels, so set
\r
193 Write Plane Enable according to which pixel we want
\r
194 to modify. The plane is determined by the two least
\r
195 significant bits of the x-coordinate: */
\r
197 outp(0x3c5, 0x01 << (x & 3));
\r
199 /* The offset of the pixel into the video segment is
\r
200 offset = (width * y + x) / 4, and write the given
\r
201 color to the plane we selected above. Heed the active
\r
202 page start selection. */
\r
203 vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;
\r
207 byte getPixel_X(int x, int y)
\r
209 /* Select the plane from which we must read the pixel color: */
\r
210 outpw(GRAC_ADDR, 0x04);
\r
211 outpw(GRAC_ADDR+1, x & 3);
\r
213 return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];
\r
217 void set320x240x256_X(void)
\r
219 /* Set the unchained version of mode 13h: */
\r
220 set320x200x256_X();
\r
222 /* Modify the vertical sync polarity bits in the Misc. Output
\r
223 Register to achieve square aspect ratio: */
\r
226 /* Modify the vertical timing registers to reflect the increased
\r
227 vertical resolution, and to center the image as good as
\r
229 outpw(0x3D4, 0x2C11); /* turn off write protect */
\r
230 outpw(0x3D4, 0x0D06); /* vertical total */
\r
231 outpw(0x3D4, 0x3E07); /* overflow register */
\r
232 outpw(0x3D4, 0xEA10); /* vertical retrace start */
\r
233 outpw(0x3D4, 0xAC11); /* vertical retrace end AND wr.prot */
\r
234 outpw(0x3D4, 0xDF12); /* vertical display enable end */
\r
235 outpw(0x3D4, 0xE715); /* start vertical blanking */
\r
236 outpw(0x3D4, 0x0616); /* end vertical blanking */
\r
238 /* Update mode info, so future operations are aware of the
\r
245 /*-----------XXXX-------------*/
\r
246 //---------------------------------------------------
\r
248 // Use the bios to get the address of the 8x8 font
\r
250 // You need a font if you are going to draw text.
\r
259 memset(&rg, 0, sizeof(rg));
\r
268 return (int far *)MK_FP(seg, off);
\r
271 void drawChar(int x, int y, int color, byte c)
\r
275 int far *font = getFont() + (c * 8);
\r
277 for (i = 0; i < 8; i++)
\r
280 for (j = 0; j < 8; j++)
\r
284 //pixel(x + j, y + i, color);
\r
285 putPixel_X(x + j, y + i, color);
\r
293 void drawText(int x, int y, int color, byte string)
\r
297 drawChar(x, y, color, string);
\r
303 /////////////////////////////////////////////////////////////////////////////
\r
305 // setvideo() - This function Manages the video modes //
\r
307 /////////////////////////////////////////////////////////////////////////////
\r
308 void setvideo(/*byte mode, */int vq){
\r
309 union REGS in, out;
\r
311 if(!vq){ // deinit the video
\r
312 // change to the video mode we were in before we switched to mode 13h
\r
314 in.h.al = old_mode;
\r
315 int86(0x10, &in, &out);
\r
317 }else if(vq == 1){ // init the video
\r
318 // get old video mode
\r
320 int86(0x10, &in, &out);
\r
321 old_mode = out.h.al;
\r
324 set320x240x256_X();
\r
328 /////////////////////////////////////////////////////////////////////////////
\r
330 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
331 // the Virtual screen. //
\r
333 /////////////////////////////////////////////////////////////////////////////
\r
334 void cls(byte color, byte *Where){
\r
335 _fmemset(Where, color, width*height);
\r
338 //color
\82Ä
\82·
\82Æ
\r
340 if(gq < NUM_COLORS){
\r
347 //color
\82Ä
\82·
\82Æ
\r
350 //---- cls(gq, vaddr);
\r
357 //slow spectrum down
\r
361 //plotpixel(xx, yy, coor, vga);
\r
362 //ppf(sx, sy, coor, vga);
\r
363 putPixel_X(sx, sy, coor);
\r
364 //printf("%d %d %d %d\n", sx, sy, svq, coor);
\r
369 if(svq == 7) coor++;
\r
370 if(sy == height && svq == 8) coor = rand()%NUM_COLORS;
\r
375 /*-----------ding-------------*/
\r
381 //++++ if(q <= 4 && q!=2 && gq == BONK-1) coor = rand()%HGQ;
\r
384 ) && gq == BONK-1){
\r
385 if(coor < HGQ && coor < LGQ) coor = LGQ;
\r
389 bakax = rand()%3; bakay = rand()%3;
\r
393 if(q == 5){ colortest(); return gq; }
\r
394 if(q == 10){ colorz(); return gq; }
\r
395 if(q == 11){ colorz(); delay(100); return gq; }
\r
396 if(q == 8){ ssd(q); /*printf("%d\n", coor);*/ }
\r
398 coor = rand()%NUM_COLORS;
\r
399 //---- cls(coor, vaddr);
\r
404 if(q == 7 || q== 9){
\r
407 if(q == 9){ ssd(q); coor++; }
\r
411 if(q<5 && gq<BONK){ // the number variable make the colors more noticable
\r
413 if(xx==width){bakax=0;}
\r
414 if(xx==0){bakax=1;}
\r
415 if(yy==height){bakay=0;}
\r
416 if(yy==0){bakay=1;}
\r
418 if(xx!=width||yy!=height){
\r
419 if(xx==0){bakax=1;bakay=-1;d3y=1;}
\r
420 if(yy==0){bakax=1;bakay=0;d3y=1;}
\r
421 if(xx==width){bakax=-1;bakay=-1;d3y=1;}
\r
422 if(yy==height){bakax=1;bakay=0;d3y=1;}
\r
423 }else if(xx==width&&yy==height) xx=yy=0;
\r
456 if(yy<0) yy=height;
\r
458 if(yy>height) yy=0;
\r
461 //---- ppf(xx, yy, coor, vga);
\r
462 putPixel_X(xx, yy, coor);
\r
463 //---- if(q==2) ppf(rand()%, rand()%height, 0, vga);
\r
464 if(q==2) putPixel_X(rand()%width, rand()%height, 0);
\r
465 if(q==2||q==4){ bakax = rand()%3; bakay = rand()%3; }
\r
467 //if(xx<0||xx>320||yy<0||yy>240)
\r
468 // printf("%d %d %d %d %d %d\n", xx, yy, coor, bakax, bakay, getPixel_X(xx,yy));
\r
469 // printf("%d\n", getPixel_X(xx,yy));
\r
471 // drawText(0, 0, 15, getPixel_X(xx,yy));
\r
478 * The library testing routines follows below.
\r
489 int p, x, y, pages;
\r
491 /* This is the way to calculate the number of pages available. */
\r
492 pages = 65536L/(widthBytes*height); // apparently this takes the A000 address
494 printf("%d\n", pages);
496 for (p = 0; p <= pages; ++p)
\r
500 /* On each page draw a single colored border, and dump the palette
\r
501 onto a small square about the middle of the page. */
504 for (x = 0; x <= width; ++x)
\r
506 putPixel_X(x, 0, p+1);
\r
507 if(p!=pages) putPixel_X(x, height-1, p+1);
508 else putPixel_X(x, 99-1, p+1);
\r
511 for (y = 0; y <= height; ++y)
\r
513 putPixel_X(0, y, p+1);
\r
514 if(p!=pages) putPixel_X(width-1, y, p+1);
515 else putPixel_X(width-1, y, p+1);
\r
518 for (x = 0; x < 16; ++x)
\r
519 for (y = 0; y < 16; ++y)
\r
520 putPixel_X(x+(p+2)*16, y+(p+2)*16, x + y*16);
\r
523 drawText(0, 0, 15, p);
527 /* Each pages will now contain a different image. Let the user cycle
\r
528 through all the pages by pressing a key. */
\r
529 for (p = 0; p <= pages; ++p)
\r
532 //drawText(0, 240, 15, "bakapi");
\r
539 * Library test (program) entry point.
\r
546 d=1; // switch variable
\r
547 key=4; // default screensaver number
\r
548 // puts("First, have a look at the 320x200 mode. I will draw some rubbish");
\r
549 // puts("on all of the four pages, then let you cycle through them by");
\r
550 // puts("hitting a key on each page.");
\r
551 // puts("Press a key when ready...");
\r
556 // puts("Then, check out Mode X, 320x240 with 3 (and a half) pages.");
\r
557 // puts("Press a key when ready...");
\r
563 /*while(d!=0){ // on!
\r
564 if(!kbhit()){ // conditions of screen saver
\r
568 // user imput switch
\r
569 printf("Enter 1, 2, 3, 4, or 6 to run a screensaver, or enter 5 to quit.\n", getch()); // prompt the user
\r
571 //if(key==3){xx=yy=0;} // crazy screen saver wwww
\r
576 while(!kbhit()){ // conditions of screen saver
\r
579 //end of screen savers
582 puts("Where to next? It's your move! wwww");
\r
583 printf("bakapi ver. 1.04.09a\nis made by sparky4
\81i
\81\86\83Ö
\81\85\81j feel free to use it ^^\nLicence: GPL v2\n");
\r