//------------------------------------------------------------------- // cgademo.cpp // // This program demonstrates early IBM-PC graphics programming // with 32KB of installed video memory (real address 0xB8000), // supporting either 2-colors or 4-colors using "packed-pixel" // memory organization, with "interlaced" scanline addressing. // (Supported by VGA/SVGA devices for backward compatibility.) // // compile using: $ g++ cgademo.cpp int86.cpp -o cgademo // // programmer: ALLAN CRUSE // written on: 01 SEP 2005 //------------------------------------------------------------------- #include // for printf(), getchar() #include // for strlen(), strncpy() #include "int86.h" // for init8086(), int86() #define VRAM_BASE_FOR_CGA 0x000B8000 typedef unsigned char u8; u8 *vram = (u8*)VRAM_BASE_FOR_CGA; void (*set_pixel)( int x, int y, int color ); struct vm86plus_struct vm; void set_pixel_1bpp( int x, int y, int color ) { int posn = (y % 2)*0x2000 + (y / 2)*80 + (x / 8); int mask = 0x80 >> (x % 8); color &= 1; color <<= 7; color >>= (x % 8); u8 temp = vram[ posn ]; temp &= ~mask; temp |= color; vram[ posn ] = temp; } void set_pixel_2bpp( int x, int y, int color ) { int posn = (y % 2)*0x2000 + (y / 2)*80 + ((2 * x) / 8); int mask = 0xC0 >> ((2 * x) % 8); color &= 3; color <<= 6; color >>= ((2 * x) % 8); u8 temp = vram[ posn ]; temp &= ~mask; temp |= color; vram[ posn ] = temp; } int main( int argc, char **argv ) { void show_text_string( int bpp, int color, char *message ); int hres, vres, minx, midx, maxx, miny, midy, maxy; int x, y, color, radius_squared; printf( "\e[H\e[J\n" ); // avoids getchar jerk init8086(); // enable BIOS service //-------------------------------------------------- // Demonstrate CGA monochrome graphics (IBM mode 6) //-------------------------------------------------- vm.regs.eax = 0x0006; // Set Display Mode 6 int86( 0x10, vm ); // invoke BIOS service hres = 640, vres = 200, set_pixel = set_pixel_1bpp; // draw screen border minx = 0, maxx = hres-1; miny = 0, maxy = vres-1; x = y = 0; color = 1; // white do { set_pixel( x, y, color ); ++x; } while ( x < maxx ); do { set_pixel( x, y, color ); ++y; } while ( y < maxy ); do { set_pixel( x, y, color ); --x; } while ( x > minx ); do { set_pixel( x, y, color ); --y; } while ( y > miny ); getchar(); // draw explanatory title show_text_string( 1, color, "CGA monochrome graphics" ); getchar(); // fill circle (unrescaled) midx = hres/2; midy = vres/2; radius_squared = 60*60; for (y = 4; y <= maxy-4; y++) for (x = 4; x <= maxx-4; x++) { int dx = x - midx; int dy = y - midy; int dist_squared = dx*dx + dy*dy; color = ( dist_squared < radius_squared ) ? 1 : 0; set_pixel( x, y, color ); } getchar(); // fill circle (adjusted) radius_squared *= 60; for (y = 4; y <= maxy-4; y++) for (x = 4; x <= maxx-4; x++) { int dx = (x - midx)*5; int dy = (y - midy)*12; int dist_squared = dx*dx + dy*dy; color = ( dist_squared < radius_squared ) ? 1 : 0; set_pixel( x, y, color ); } getchar(); //--------------------------------------------- // Demonstrate CGA color graphics (IBM mode 5) //--------------------------------------------- vm.regs.eax = 0x0005; // Set Display Mode 5 int86( 0x10, vm ); // invoke BIOS service hres = 320, vres = 200, set_pixel = set_pixel_2bpp; // draw screen border color = 3; // white minx = 0, maxx = hres-1; miny = 0, maxy = vres-1; x = y = 0; do { set_pixel( x, y, color ); ++x; } while ( x < maxx ); do { set_pixel( x, y, color ); ++y; } while ( y < maxy ); do { set_pixel( x, y, color ); --x; } while ( x > minx ); do { set_pixel( x, y, color ); --y; } while ( y > miny ); getchar(); // draw explanatory title show_text_string( 2, color, "CGA color graphics" ); getchar(); // fill circle (unrescaled) midx = hres/2; midy = vres/2; radius_squared = 60*60; for (y = 4; y <= maxy-4; y++) for (x = 4; x <= maxx-4; x++) { int dx = x - midx; int dy = y - midy; int dist_squared = dx*dx + dy*dy; color = ( dist_squared < radius_squared ) ? 1 : 2; set_pixel( x, y, color ); } getchar(); // fill circle (adjusted) radius_squared *= 30; for (y = 4; y <= maxy-4; y++) for (x = 4; x <= maxx-4; x++) { int dx = (x - midx)*5; int dy = (y - midy)*6; int dist_squared = dx*dx + dy*dy; color = ( dist_squared < radius_squared ) ? 1 : 2; set_pixel( x, y, color ); } getchar(); // return the display to standard text-mode vm.regs.eax = 0x0003; // Set Display Mode 3 int86( 0x10, vm ); // invoke BIOS service printf( "finished\n" ); } void show_text_string( int bpp, int color, char *message ) { // compute message's length and screen-centering parameters int msglen = strlen( message ); int col = (80/bpp - msglen)/2; int row = 12; int rowcol = (row << 8) | col; // copy the message to an 8086-addressable memory-location strncpy( (char*)0x00018000, message, msglen ); // so a standard BIOS service can put that message on-screen vm.regs.eax = 0x1300; // BIOS drawstring function vm.regs.es = 0x1000; // string's segment-address vm.regs.ebp = 0x8000; // string's offset-address vm.regs.ecx = msglen; // string's size (in bytes) vm.regs.ebx = color; // string's foreground color vm.regs.edx = rowcol; // string's screen-coordinates int86( 0x10, vm ); // invoke ROM-BIOS service }