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
42 * We 'require' a large data model simply to get rid of explicit 'far'
\r
43 * pointers and compiler specific '_fmemset()' functions and the likes.
\r
45 #if !defined(__COMPACT__)
\r
46 # if !defined(__LARGE__)
\r
47 # if !defined(__HUGE__)
\r
48 # error Large data model required! Try compiling with 'wcc -0 -ml lib.c'.
\r
57 //code from old library!
\r
59 #include "dos_gfx.h"
\r
62 //color
\82Ä
\82·
\82Æ
\r
66 int bakax = 0, bakay = 0;
\r
67 cord xx = rand()&0%320, yy = rand()&0%240, sx = 0, sy = 0;
\r
71 * Comment out the following #define if you don't want the testing main()
\r
77 * Define the port addresses of some VGA registers.
\r
79 #define CRTC_ADDR 0x3d4 /* Base port of the CRT Controller (color) */
\r
81 #define SEQU_ADDR 0x3c4 /* Base port of the Sequencer */
\r
82 #define GRAC_ADDR 0x3ce /* Base port of the Graphics Controller */
\r
83 #define STATUS_ADDR 0x3DA
\r
87 * Make a far pointer to the VGA graphics buffer segment. Your compiler
\r
88 * might not have the MK_FP macro, but you'll figure something out.
\r
90 byte *vga = (byte *) MK_FP(0xA000, 0);
\r
94 * width and height should specify the mode dimensions. widthBytes
\r
95 * specify the width of a line in addressable bytes.
\r
97 unsigned width, height, widthBytes;
\r
100 * actStart specifies the start of the page being accessed by
\r
101 * drawing operations. visStart specifies the contents of the Screen
\r
102 * Start register, i.e. the start of the visible page.
\r
104 unsigned actStart, visStart;
\r
107 * set320x200x256_X()
\r
108 * sets mode 13h, then turns it into an unchained (planar), 4-page
\r
109 * 320x200x256 mode.
\r
111 void set320x200x256_X(void)
\r
115 /* Set VGA BIOS mode 13h: */
\r
117 int86(0x10, &r, &r);
\r
119 /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */
\r
120 outpw(SEQU_ADDR, 0x0604);
\r
122 /* Turn off word mode, by setting the Mode Control register
\r
123 of the CRT Controller (index 0x17, port 0x3d4): */
\r
124 outpw(CRTC_ADDR, 0xE317);
\r
126 /* Turn off doubleword mode, by setting the Underline Location
\r
127 register (index 0x14, port 0x3d4): */
\r
128 outpw(CRTC_ADDR, 0x0014);
\r
130 /* Clear entire video memory, by selecting all four planes, then
\r
131 writing 0 to entire segment. */
\r
132 outpw(SEQU_ADDR, 0x0F02);
\r
133 memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */
\r
136 /* Update the global variables to reflect dimensions of this
\r
137 mode. This is needed by most future drawing operations. */
\r
141 /* Each byte addresses four pixels, so the width of a scan line
\r
142 in *bytes* is one fourth of the number of pixels on a line. */
\r
143 widthBytes = width / 4;
\r
145 /* By default we want screen refreshing and drawing operations
\r
146 to be based at offset 0 in the video segment. */
\r
147 actStart = visStart = 0;
\r
152 * setActiveStart() tells our graphics operations which address in video
\r
153 * memory should be considered the top left corner.
\r
155 void setActiveStart(unsigned offset)
\r
161 * setVisibleStart() tells the VGA from which byte to fetch the first
\r
162 * pixel when starting refresh at the top of the screen. This version
\r
163 * won't look very well in time critical situations (games for
\r
164 * instance) as the register outputs are not synchronized with the
\r
165 * screen refresh. This refresh might start when the high byte is
\r
166 * set, but before the low byte is set, which produces a bad flicker.
\r
168 void setVisibleStart(unsigned offset)
\r
171 outpw(CRTC_ADDR, 0x0C); /* set high byte */
\r
172 outpw(CRTC_ADDR+1, visStart >> 8);
\r
173 outpw(CRTC_ADDR, 0x0D); /* set low byte */
\r
174 outpw(CRTC_ADDR+1, visStart & 0xff);
\r
178 * setXXXPage() sets the specified page by multiplying the page number
\r
179 * with the size of one page at the current resolution, then handing the
\r
180 * resulting offset value over to the corresponding setXXXStart()
\r
181 * function. The first page is number 0.
\r
183 void setActivePage(int page)
\r
185 setActiveStart(page * widthBytes * height);
\r
188 void setVisiblePage(int page)
\r
190 setVisibleStart(page * widthBytes * height);
\r
193 void putPixel_X(int x, int y, byte color)
\r
195 /* Each address accesses four neighboring pixels, so set
\r
196 Write Plane Enable according to which pixel we want
\r
197 to modify. The plane is determined by the two least
\r
198 significant bits of the x-coordinate: */
\r
200 outp(0x3c5, 0x01 << (x & 3));
\r
202 /* The offset of the pixel into the video segment is
\r
203 offset = (width * y + x) / 4, and write the given
\r
204 color to the plane we selected above. Heed the active
\r
205 page start selection. */
\r
206 vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;
\r
210 byte getPixel_X(int x, int y)
\r
212 /* Select the plane from which we must read the pixel color: */
\r
213 outpw(GRAC_ADDR, 0x04);
\r
214 outpw(GRAC_ADDR+1, x & 3);
\r
216 return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];
\r
220 void set320x240x256_X(void)
\r
222 /* Set the unchained version of mode 13h: */
\r
223 set320x200x256_X();
\r
225 /* Modify the vertical sync polarity bits in the Misc. Output
\r
226 Register to achieve square aspect ratio: */
\r
229 /* Modify the vertical timing registers to reflect the increased
\r
230 vertical resolution, and to center the image as good as
\r
232 outpw(0x3D4, 0x2C11); /* turn off write protect */
\r
233 outpw(0x3D4, 0x0D06); /* vertical total */
\r
234 outpw(0x3D4, 0x3E07); /* overflow register */
\r
235 outpw(0x3D4, 0xEA10); /* vertical retrace start */
\r
236 outpw(0x3D4, 0xAC11); /* vertical retrace end AND wr.prot */
\r
237 outpw(0x3D4, 0xDF12); /* vertical display enable end */
\r
238 outpw(0x3D4, 0xE715); /* start vertical blanking */
\r
239 outpw(0x3D4, 0x0616); /* end vertical blanking */
\r
241 /* Update mode info, so future operations are aware of the
\r
248 /*-----------XXXX-------------*/
\r
250 /////////////////////////////////////////////////////////////////////////////
\r
252 // WaitRetrace() - This waits until you are in a Verticle Retrace. //
\r
254 /////////////////////////////////////////////////////////////////////////////
\r
255 void wait_for_retrace(void)
\r
257 while (!(inp(STATUS_ADDR) & 0x08));
\r
261 //king_crimson's code
\r
262 void putColorBox_X(int x, int y, int w, int h, byte color) {
\r
267 for (curx=x; curx<(x+w); curx++) {
\r
268 outp(0x3c5, 0x01 << (curx & 3));
\r
269 drawptr = (unsigned)(widthBytes * y) + (curx / 4) + actStart;
\r
270 for (cury=0; cury<h; cury++) {
\r
271 vga[drawptr] = color;
\r
272 drawptr += widthBytes;
\r
277 void vScroll(int rows)
\r
279 // Scrolling = current start + (rows * bytes in a row)
\r
280 setVisibleStart(visStart + (rows * width));
\r
283 void scrolly(int bongy)
\r
291 for(int ti=0;ti<TILEWH;ti++)
\r
298 //king_crimson's code
\r
299 void hScroll(int Cols) {
\r
300 wait_for_retrace();
\r
302 outp(0x3C0, Cols & 3);
\r
304 outp(0x3D5, Cols >> 2);
\r
306 //setVisibleStart(visStart + (Cols * height));
\r
307 setVisibleStart(visStart + (Cols * width));
\r
310 /////////////////////////////////////////////////////////////////////////////
\r
312 // setvideo() - This function Manages the video modes //
\r
314 /////////////////////////////////////////////////////////////////////////////
\r
315 void setvideo(/*byte mode, */int vq){
\r
316 union REGS in, out;
\r
318 if(!vq){ // deinit the video
\r
319 // change to the video mode we were in before we switched to mode 13h
\r
320 //mxSetMode( MX_TEXT );
\r
323 in.h.al = old_mode;
\r
324 int86(0x10, &in, &out);
\r
326 }else if(vq == 1){ // init the video
\r
327 // get old video mode
\r
329 int86(0x10, &in, &out);
\r
330 old_mode = out.h.al;
\r
334 mxSetMode( MX_320x240 );
\r
337 // mxSetVirtualScreen(width+(width/4), height+(height/4));
\r
338 // mxSetVirtualScreen(width*2, height*2);
\r
339 //set320x240x256_X();
\r
340 mxSetVirtualScreen(560,420);
\r
341 // mxSetVirtualScreen((640-(TILEWH*2)),(480-(TILEWH*2)));
\r
343 //mxSetClipRegion(0, 0, width, height);
\r
347 /////////////////////////////////////////////////////////////////////////////
\r
349 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
350 // the Virtual screen. //
\r
352 /////////////////////////////////////////////////////////////////////////////
\r
353 void cls(byte color, byte *Where){
\r
354 _fmemset(Where, color, width*(height*17));
\r
357 //color
\82Ä
\82·
\82Æ
\r
359 if(gq < NUM_COLORS){
\r
366 //color
\82Ä
\82·
\82Æ
\r
369 //---- cls(gq, vaddr);
\r
376 //slow spectrum down
\r
380 //plotpixel(xx, yy, coor, vga);
\r
381 //ppf(sx, sy, coor, vga);
\r
382 putPixel_X(sx, sy, coor);
\r
383 //printf("%d %d %d %d\n", sx, sy, svq, coor);
\r
388 if(svq == 7) coor++;
\r
389 if(sy == height && svq == 8) coor = rand()%NUM_COLORS;
\r
394 /*-----------ding-------------*/
\r
401 if((height)<yy<(height*2)){
\r
405 if((height*2)<yy<(height*3)){
\r
411 //++++ if(q <= 4 && q!=2 && gq == BONK-1) coor = rand()%HGQ;
\r
416 if(coor < HGQ && coor < LGQ) coor = LGQ;
\r
420 bakax = rand()%3; bakay = rand()%3;
\r
424 if(q==8){ colorz(); return gq; }else
\r
425 if(q==10){ ssd(q); /*printf("%d\n", coor);*/ }else
\r
426 if(q==5){ colortest(); return gq; }else
\r
427 if(q==11){ colorz(); delay(100); return gq; }
\r
429 coor = rand()%NUM_COLORS;
\r
430 //---- cls(coor, vaddr);
\r
438 if(q == 9){ ssd(q); coor++; }
\r
442 if((q<5 && gq<BONK) || (q==16 && gq<BONK)){ // the number variable make the colors more noticable
\r
444 if(xx==width){bakax=0;}
\r
445 if(xx==0){bakax=1;}
\r
446 if(yy==height){bakay=0;}
\r
447 if(yy==0){bakay=1;}
\r
449 if(xx!=width||yy!=height){
\r
450 if(xx==0){bakax=1;bakay=-1;d3y=1;}
\r
451 if(yy==0){bakax=1;bakay=0;d3y=1;}
\r
452 if(xx==width){bakax=-1;bakay=-1;d3y=1;}
\r
453 if(yy==height){bakax=1;bakay=0;d3y=1;}
\r
454 }else if(xx==width&&yy==height) xx=yy=0;
\r
505 if(xx<0) xx=(560/*-TILEWH*/);
\r
506 if(yy<0) yy=(420/*-TILEWH*/);
\r
507 if(xx>(560/*-TILEWH*/)) xx=0;
\r
508 if(yy>(420/*-TILEWH*/)) yy=0;
\r
511 //interesting effects
\r
517 mxPutPixel(tx, ty, coor);
\r
518 //drawrect(tx, ty, tx+TILEWH, ty+TILEWH, coor);
\r
519 //printf("%d %d %d %d %d %d\n", xx, yy, tx, ty, TILEWH);
\r
522 //---- ppf(xx, yy, coor, vga);
\r
523 }else /*if(xx>=0 && xx<width && yy>=0 && yy<(height*3))*/{
\r
524 // mxFillBox(xx, yy, TILEWH, TILEWH, coor, 0);
\r
526 // putPixel_X(xx, yy, coor);
\r
527 mxPutPixel(xx, yy, coor);
\r
530 //---- if(q==2) ppf(rand()%, rand()%height, 0, vga);
\r
531 // if(q==2) putColorBox_X(rand()%width, rand()%(height*3), TILEWH, TILEWH, 0);
\r
533 if(q==2) mxPutPixel(rand()%width, rand()%(height*3), 0);
\r
534 if(q==16) mxPutPixel(rand()%width, rand()%(height*3), 0);
\r
535 if(q==2||q==4||q==16){ bakax = rand()%3; bakay = rand()%3; }
\r
537 //if(xx<0||xx>320||yy<0||yy>(height*3))
\r
538 // printf("%d %d %d %d %d %d\n", xx, yy, coor, bakax, bakay, getPixel_X(xx,yy));
\r
539 // printf("%d\n", getPixel_X(xx,yy));
\r
546 * The library testing routines follows below.
\r
557 int p, x, y, pages;
\r
559 /* This is the way to calculate the number of pages available. */
\r
560 pages = 65536L/(widthBytes*height); // apparently this takes the A000 address
\r
561 // if(height==240) pages++;
\r
563 // printf("%d\n", pages);
\r
565 for (p = 0; p <= pages; ++p)
\r
569 /* On each page draw a single colored border, and dump the palette
\r
570 onto a small square about the middle of the page. */
\r
573 for (x = 0; x <= width; ++x)
\r
575 // putPixel_X(x, 0, p+1);
\r
576 mxPutPixel(x, 0, p+1);
\r
577 if(p!=pages) mxPutPixel(x, height-1, p+1);
\r
578 else if(height==240) mxPutPixel(x, 99-1, p+1);
\r
581 for (y = 0; y <= height; ++y)
\r
583 mxPutPixel(0, y, p+1);
\r
584 if(p!=pages) mxPutPixel(width-1, y, p+1);
\r
585 else if(height==240) mxPutPixel(width-1, y, p+1);
\r
588 for (x = 0; x < TILEWH; ++x)
\r
589 for (y = 0; y < TILEWH; ++y)
\r
590 mxPutPixel(x+(p+2)*16, y+(p+2)*TILEWH, x + y*TILEWH);
\r
595 /* Each pages will now contain a different image. Let the user cycle
\r
596 through all the pages by pressing a key. */
\r
597 for (p = 0; p < pages; ++p)
\r
606 * Library test (program) entry point.
\r
611 int key,d,xpos,ypos,xdir,ydir;
\r
614 d=1; // switch variable
\r
615 key=4; // default screensaver number
\r
620 // puts("First, have a look at the 320x200 mode. I will draw some rubbish");
\r
621 // puts("on all of the four pages, then let you cycle through them by");
\r
622 // puts("hitting a key on each page.");
\r
623 // puts("Press a key when ready...");
\r
628 // puts("Then, check out Mode X, 320x240 with 3 (and a half) pages.");
\r
629 // puts("Press a key when ready...");
\r
636 /*while(d!=0){ // on!
\r
637 if(!kbhit()){ // conditions of screen saver
\r
641 // user imput switch
\r
642 printf("Enter 1, 2, 3, 4, or 6 to run a screensaver, or enter 5 to quit.\n", getch()); // prompt the user
\r
644 //if(key==3){xx=yy=0;} // crazy screen saver wwww
\r
649 while(!kbhit()){ // conditions of screen saver
\r
652 //end of screen savers
\r
654 for (int x = 0; x < width; ++x)
\r
656 mxPutPixel(x, 0, 15);
\r
657 mxPutPixel(x, height-1, 15);
\r
659 for (int y = 0; y < height; ++y)
\r
661 mxPutPixel(0, y, 15);
\r
662 mxPutPixel(width-1, y, 15);
\r
670 //for(int i=0;i<TILEWH;i++){
\r
676 if( (xpos>239) || (xpos<1))xdir=-xdir;
\r
677 if( (ypos>179) || (ypos<1))ydir=-ydir; // { Hit a boundry, change
\r
682 printf("wwww\n%dx%d\n", width,height);
\r
683 printf("[%d]\n", mxGetVersion());
\r
684 puts("where to next? It's your move! wwww");
\r
685 printf("bakapi ver. 1.04.09.04\nis made by sparky4
\81i
\81\86\83Ö
\81\85\81j feel free to use it ^^\nLicence: GPL v2\n");
\r