PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 1/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. // A graphics library demonstrating the simplicity of fast // graphics in 320x200x256-color VGA mode. The code is not // fully optimized but it is pretty close; an extra 5% or so // might be squeezed out of the putimage() for example. Be // careful when altering pseuodoregisters; while doing one // load the compiler may trash another register which was just // loaded with something pertinent. // Functions provided include point, row, and array (image) // drawing functions, as well as palette functions using BIOS // and line-drawing and circle-drawing functions. // Main() demonstrates most of the functions in a pretty and // interesting way. void GrInit(void); void GrClose(void); unsigned char GetPixel(unsigned int x, unsigned int y); void PutPixel(unsigned int x, unsigned int y, unsigned char color); void FillRow(unsigned x, unsigned y, unsigned char color, unsigned length); void PutRow(unsigned x, unsigned y, char *data, unsigned length); void GetRow(unsigned x, unsigned y, char *data, unsigned length); void PutImage(unsigned x, unsigned y, char *data, unsigned rows, unsigned cols); void GetImage(unsigned x, unsigned y, char *data, unsigned rows, unsigned cols); void GetAllPalette(char (*palette)[3]); void SetAllPalette( char (*palette)[3]); void Circle(int x, int y, int radius, unsigned char color); void Line(unsigned x1, unsigned y1, unsigned x2, unsigned y2, unsigned char color); #define VIDEOINT 0x10 #pragma inline PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 2/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. // 'dos.h' is essential #include // we need 'math.h' for sqrt() in Circle() and abs() in Line() #include // we need 'conio.h' for getch() #include int rowOffset[200]; // as an optimization, // rowOffset will be used as a table to // avoid the multiplication column+(320*row) // when getting the actual memory address of // a pixel or a row // GrInit() initializes the rowOffset table and switches video // modes to 320x200 with 256 colors void GrInit() { int i; // Pre-setup our multipications for column, //row -> screen address for (i=0; i<200; ++i) { rowOffset[i]=i*320; } // Set video mode to 320x200 -- // sophisticated users may wish to research checking // for the availability of VGA/MCGA prior to switching // modes. _AH=0; _AL=0x13; geninterrupt(VIDEOINT); } // GrClose sets the video back into text mode void GrClose() { // set video mode 80x25 color text -- we're assuming // that that's available PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 3/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. // if we're using VGA _AH=0; _AL=0x3; geninterrupt(VIDEOINT); } // GetPixel returns the pixel value at a given (x,y) screen // location unsigned char GetPixel(unsigned int x, unsigned int y) { return *((char far *) 0xA0000000L+ (x+rowOffset[y])); } // PutPixel changes the pixel at a given (x,y) screen location // to value 'color' void PutPixel( unsigned int x, unsigned int y, unsigned char color) { *((char far *) 0xA0000000L + (x+rowOffset[y]))=color; } // FillRow writes a row of 'color' color pixels of length // 'length' starting at screen location (x,y). void FillRow( unsigned x, unsigned y, unsigned char color, unsigned length ) { _ES=0xA000; // The segment for screen memory _DI=x+rowOffset[y]; // The offset in screen to write at _CX=length; // Number of bytes for rep stosb _AL=color; // The value stosb will store in video // memory asm { cld // set direction flag so DI // will increment rep stosb // zap a row of color AL out to // video memory al->[es:di] } PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 4/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. } // PutRow transfers a row of pixels from 'data' to screen // starting at (x,y) and continuing for 'length'. A rep // movsw instead of rep movsb might optimize this slightly for // even-length rows void PutRow(unsigned x, unsigned y, char *data, unsigned length) { // You may remove all lines marked with '***' if 'data' is a // near pointer (i.e. if 'data' was not allocated from the far // heap and was not declared as 'far' data.) Remove them all // if you remove any. _ES=0xA000; _DI=x+rowOffset[y]; // the offset in video memory for // the row start _SI=FP_OFF(data); // load AX last since many C // instructions will trash AX _AX=FP_SEG(data); // store data's segment in AX for // now *** asm { push ds // Save DS since we're going to // alter it *** mov ds,ax // load register from AX (loaded // above) *** mov cx,length // we're moving 'length' bytes // total cld // clear the direction flag to // increment si and di rep movsb // dump the whole row out to video // memory [ds:si]->[es:di] pop ds // Restore DS *** } } // GetRow() copies a row of pixels of length 'length' out of // video memory into the buffer at 'data'. rep movsw might be // slightly faster here also. PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 5/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. void GetRow(unsigned x, unsigned y, char *data, unsigned length) { _SI=x+rowOffset[y]; // the offset in video memory for // the row start _ES=FP_SEG(data); // set up ES:DI to point to data _DI=FP_OFF(data); _AX=0xA000; // load video segment in AX asm { push ds // save DS since we have to use DS // for copying mov ds,ax // load DS with segment for video // memory from AX (0xA000) mov cx,length // we're moving 'length' bytes // total cld // clear the direction flag to // increment si and di rep movsb // get the whole row from video // memory [ds:si]->[es:di] pop ds // Restore DS } } // GetImage() uses repeated GetRow's to store a screen image // in buffer at 'data' void GetImage( unsigned x, unsigned y, char *data, unsigned columns, unsigned rows) { int i; for (i=0; iyDiff) { xInc=1L<<16; yInc=yDiff/(xDiff>>16); } else { xInc=xDiff/(yDiff>>16); yInc=1L<<16; } if (x2 < x1) xInc= -xInc; if (y2 < y1) yInc= -yInc; x=((long) x1) << 16; y=((long) y1) << 16; do { screenX=(x+32767L)>>16; screenY=(y+32767L)>>16; PutPixel(screenX,screenY,color); x+=xInc; y+=yInc; } while (screenX!=x2 || screenY!=y2); PutPixel(x2,y2,color); // wrap up the line else we will be // stopping one pixel before the // end } // Just for fun, a slightly optimized circle drawing routine void Circle(int centerX, int centerY, int radius, unsigned char color) { int i,newY,radiusSquared,distance; radiusSquared=radius*radius; // sqrt(2)/2*radius is the horizontal or vertical portion // of 1/8 circle distance=sqrt(2.0)/2.0*radius; // as an optimization, we will just do 1/8 of a circle and // do 7 other pixels as reflections, since a circle has // 8-way symmetry -- all those SQRT's // can take time! Superfast SQRT's might be done with a // lookup table. for (i=0; i<=distance; ++i) { PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 9/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. // the formula for a circle is x^2+y^2=radius^2 newY=sqrt(radiusSquared-i*i); PutPixel(centerX+i, centerY+newY,color); PutPixel(centerX-i, centerY-newY,color); PutPixel(centerX+i, centerY-newY,color); PutPixel(centerX-i, centerY+newY,color); PutPixel(centerX+newY,centerY+i,color); PutPixel(centerX-newY,centerY-i,color); PutPixel(centerX+newY,centerY-i,color); PutPixel(centerX-newY,centerY+i,color); } } #define ROWSIZE 34 char logo[5][ROWSIZE]= { 1,1,1,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,0, 1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1, 1,1,1,0,0,1,0,0,1,0,1,1,1,0,0,1,0,0,0,0,1,1,1,1,0,1,0,1,1,0,1,0,0,1, 1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1, 1,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,0,1,0,0,1,0,1,0,0,1,0,1,1,1,0 }; char image[2700]; int main() { int i,j, k; char palette[256][3], tempRed, tempGreen, tempBlue; char *temp,color; GrInit(); // Demonstrate Line function i=15; for (j=199; j>0; j-=10) { Line(0,j,i,0,j/10+16); PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 10/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. i += 16 ; } // Demonstrate FillRow function with a series of rows. for (i=92; i<=108; i+=2) { FillRow(136,i,7,49); } // Put BORLAND logo down PutImage(145,98,&(logo[0][0]),ROWSIZE,5); // Draw a circle around it Circle(160,100,25,3); getch(); // pause to let the user admire our // work! // and now some fancy stuff; // we will get the image and 'shade' it by incrementing the // color according to the column+row GetImage(134,74,image,52,52); temp=image; for (i=0; i<52; ++i) { for (j=0; j<52; ++j) { if (*temp!=0) { // change BORLAND to 128 higher for contrast if (*temp==1) *temp=(*temp+i+j+128)%256; else *temp=(*temp+i+j)%256; } ++temp; } } // put the altered image back down PutImage(134,74,image,52,52); GetAllColors(palette); // now we'll 'rotate' the palette by 1 forever, by copying // all the colors down to the next lower color, until a key // is hit. Palette entry 0 is not altered, otherwise the PRODUCT : Borland C++ NUMBER : 1031 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 11/11 TITLE : Some Graphics primitives using 256-Color VGA Mode. // background for the whole screen would be flashing. while (!kbhit()) { tempRed=palette[1][0]; tempGreen=palette[1][1]; tempBlue=palette[1][2]; for (j=2; j<256; ++j) { for (k=0; k<3; ++k) palette[j-1][k]=palette[j][k]; } palette[255][0]=tempRed; palette[255][1]=tempGreen; palette[255][2]=tempBlue; delay(15); SetAllColors(palette); } GrClose(); return(0); } DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.