//------------------------------------------------------------------- // drawtext.cpp // // This program shows how a graphics application can draw text, // based on a character glyph-table stored in the VGA firmware. // We can draw the text against an existing colored pattern and // we can put our text at an arbitrary pixel-location onscreen. // // compile using: $ g++ drawtext.cpp int86.cpp -o drawtext // // programmer: ALLAN CRUSE // written on: 05 SEP 2005 //------------------------------------------------------------------- #include // for printf(), perror() #include // for inb(), outb() #include "int86.h" // for init8086(), int86() #define VRAM_BASE_ADDRESS 0x000A0000 #define GC_PORT 0x03CE unsigned char *vram = (unsigned char*)VRAM_BASE_ADDRESS; struct vm86plus_struct vm; int vga_mode = 18, hres = 640, vres = 480; char pattern[] = { 0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 }; void draw_character( int x, int y, int color, char *glyph ) { int which = y * hres + x; int where = which / 8; int shift = which % 8; int mask = 0xFF >> shift; // Here we use VGA Write Mode 3 ("Masked Write") outw( 0x0305, GC_PORT ); // Write Mode 3 outw( (color<<8) | 0, GC_PORT ); // Set/Reset outw( (shift<<8) | 3, GC_PORT ); // Data-Rotate register // pass one draws the glyph's left-hand portion outw( (mask<<8) | 8, GC_PORT ); // left-hand Bit Mask for (int row = 0; row < 16; row++) { int temp = vram[ where + 80*row ]; // load latches vram[ where + 80*row ] = glyph[ row ]; // draw fgcolor } ++where; // the byte-address following the starting cell if (( shift == 0 )||( (where % 80) == 0 )) return; // pass two draws the glyph's right-hand portion outw( (~mask<<8) | 8, GC_PORT ); // right-hand Bit Mask for (int row = 0; row < 16; row++) { int temp = vram[ where + 80*row ]; // load latches vram[ where + 80*row ] = glyph[ row ]; // draw fgcolor } } void put_pixel( int x, int y, int color ) { int which = y * hres + x; int where = which / 8; int shift = which % 8; int mask = 0x80 >> shift; outw( (mask<<8) | 8, GC_PORT ); // Bit Mask outw( (color<<8) | 0, GC_PORT ); // Set/Reset outw( 0x0F01, GC_PORT ); // Enable Set/Reset vram[ where ] = vram[ where ]; // "Direct Write" } void bios_write_string( int row, int col, int color, char *msg ) { // restore defaults to GC registers outw( 0x0000, GC_PORT ); // Set/Reset outw( 0x0001, GC_PORT ); // Enable Set/Reset outw( 0x0003, GC_PORT ); // Data-Rotate/Function-Select outw( 0x0005, GC_PORT ); // Write Mode 0 ("Direct Write") outw( 0xFF08, GC_PORT ); // Bit Mask // copy string to real-mode memory (and determine length) char *src = (char*)0x18000; int length = 0; while ( src[ length ] = msg[ length ] ) ++length; // setup register-parameters and invoke int-0x10, function 0x13 vm.regs.ecx = length; vm.regs.es = ((int)src >> 4); vm.regs.ebp = 0; vm.regs.ebx = (color & 0xFF); vm.regs.edx = (row << 8) | (col & 0xFF); vm.regs.eax = 0x1300; int86( 0x10, vm ); } int main( int argc, char **argv ) { // initialize environment for executing ROM-BIOS services init8086(); // now locate the 8x16 character-glyph table in firmware vm.regs.eax = 0x1130; // Get Font Information vm.regs.ebx = 0x0600; // address of 8x16 font int86( 0x10, vm ); // invoke BIOS service char *font = (char*)(vm.regs.es * 16L + vm.regs.ebp); printf( "\e[H\e[J\nAddress of 8x16 font: %08X \n", (int)font ); getchar(); // enter graphics mode (640-by480, 16-colors) vm.regs.eax = vga_mode; // Set Display Mode 18 int86( 0x10, vm ); // invoke BIOS service // draw a white screen border int xmin = 0, xmax = hres-1, ymin = 0, ymax = vres-1; int x = 0, y = 0, color = 15; do { put_pixel( x, y, color ); ++x; } while ( x < xmax ); do { put_pixel( x, y, color ); ++y; } while ( y < ymax ); do { put_pixel( x, y, color ); --x; } while ( x > xmin ); do { put_pixel( x, y, color ); --y; } while ( y > ymin ); getchar(); // tile part of the bordered area with a two-color pattern xmin = 1, ymin = 8, xmax = 79, ymax = 470; int fg = 9; // foreground color is normal blue int bg = 1; // background color is bright blue outw( (bg<<8) | 0, GC_PORT ); outw( (fg<<8) | 1, GC_PORT ); outw( 0x0005, GC_PORT ); // Write Mode 0 ("Direct Write") outw( 0xFF08, GC_PORT ); // Bit Mask enables all pixels outw( 0x0003, GC_PORT ); // Data-Rotation/Function-Select for (y = ymin; y < ymax; y++) for (x = xmin; x < xmax; x++) vram[ y * 80 + x ] = pattern[ y % 8 ]; getchar(); // draw a text message using the BIOS 'WriteString' function char message[] = " Hello, world! "; int row = 4, col = 34, green = 0x0A; // bright green bios_write_string( row, col, green, message ); getchar(); // draw some text messages against our patterned background int len = sizeof( message ) - 1; color = green; do { ++row; y = row * 36; x = (col * 8) + color; for (int i = 0; i < len; i++) { char *cp = font + 16*message[i]; draw_character( x, y, color, cp ); x += 8; } getchar(); } while ( ++color < 16 ); // restore text mode vm.regs.eax = 0x0003; int86( 0x10, vm ); printf( "End of \'drawtext\' demo \n" ); }