Graphics Bitmaps Drawing characters glyphs and multicolor patterns Limitations of BIOS routines • Last time we used a ROM-BIOS routine to draw a text message on a graphics screen (i.e., the so-called ‘write_string’ service) • But some limitations were apparent: – String-location had to conform to a cell-grid – Background color pattern was obliterated • We can overcome both these limitations if we draw the character-glyphs ourselves Built-in character bitmaps • The ROM-BIOS has full sets of bitmaps for the images of all the ASCII characters in several sizes (e.g., 8x8, 8x14 and 8x16) Example: An 8-by-8 glyph for the letter ‘H’ Layout of 8x16 glyph-table • The Glyph-Table is an array of bit-images • Each bit-image is 16-bytes in length • Each ascii-code serves as array-index 0x40 0x41 0x42 0x43 0x44 0x45 0x46 ‘@’ ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ ‘F’ etc The 8086 physical memory The VGA firmware Character-Glyph tables are located in this region Boot ROM 0xF0000 Reserved for add-ins Video ROM 0xC0000 VRAM 0xA0000 EBDA 1-MB A built-in BIOS function will report each of the glyph-table start-locations RAM BIOS DATA VECTORS 0x00000 Finding the ROM fonts • Standard BIOS service locates ROM fonts • Designed to execute in 8086 real-mode • Normal service-call protocol is followed: – Parameters are placed in CPU registers – Software interrupt instruction is executed – ROM-BIOS code performs desired service – Parameters may be returned in registers Example # AT&T assembly language syntax mov $0x11, %ah # char. gen. services mov $0x30, %al # get font information mov $6, %bh # 8x16 font address int $0x10 # request BIOS service # the font address is returned in ES:BP # (and count of scanlines should be in CX) Invoking BIOS from Linux • Include our “int86.h” header-file • Define ‘struct vm86plus_struct’ object: vm • Initialize necessary register-fields of ‘vm’ – vm.regs.eax = 0x1130; – vm.regs.ebx = 0x0600; • Call our function: int86( 0x10, vm ); • Retrieve the returned parameters from vm – e.g., from ‘vm.regs.es’ and ‘vm.regs.ebp’ Drawing a character (in mode 18) • • • • • • Must enable I/O and 1-MB memory-map Virtual address of VRAM is 0x000A0000 Use any ascii-code as a glyph-table index Use x,y coordinates for character location Specify the character’s ‘foreground color’ Thus your function-call could look like: draw_char( x, y, color, ascii ); Using VGA Write Mode 3 • To preserve the background pattern when a character-glyph is drawn, you can use a ‘Masked Write’ operation (‘Write Mode 3’) • To position the character at an arbitrary horizontal pixel position, use Data-Rotate • The foreground color goes in ‘Set/Reset’ • The Bit Mask register prevents unwanted pixels from being drawn when rotation Illustration Adjacent bytes on the screen Character-glyph is right-rotated Afterward this rotated glyph gets ‘masked’ Left-hand Bit Mask Right-hand Bit Mask Implementation details void draw_char( int x, int y, int fg, int ascii ) { int which = y * hres + x; int where = which / 8; int shift = which % 8; int left_mask = 0xFF >> shift; int right_mask = ~(left_mask); char *glyph = (char*)fontbase + 16*ascii; Draw_char() (continued) outw( 0x0305, GCPORT ); // use Mode 3 outw( color<<8, GCPORT ); // Set/Reset // first-pass draws glyph’s left portion outw( (left_mask<<8) | 8, GCPORT ); for (int row = 0; row < 16; row++) { char temp = vram[ where + row*80 ]; vram[ where + row*80 ] = glyph[ row ]; } Draw_char() (concluded) if ( shift == 0 ) return; // we can do an early exit // else second-pass draws glyph’s right portion ++where; // location of the adjacent byte outw( (right_mask<<8) | 8, GCPORT ); // Bit Mask for (int row = 0; row < 16; row++) { char temp = vram[ where + row*80 ]; vram[ where + row*80 ] = glyph[ row ]; } } Our ‘drawtext.cpp’ demo • We used an 8-by-8 bitmap to generate the patterned background for drawing text on Background color 0001 (binary) Foreground color 1001 (binary) 0x00 0x00 0x33 0x33 0x00 0x00 0x33 0x33 How ‘Write Mode 0’ works Byte from pattern-glyph ENABLE SET/RESET 0 0 1 1 0 0 1 1 Data from CPU SET/RESET 0 x 0 0 1 1 0 0 1 1 Latch plane 3 1 0 0 0 0 0 0 0 0 0 Latch plane 2 1 0 0 0 0 0 0 0 0 0 Latch plane 1 1 1 1 1 1 1 1 1 1 1 Latch plane 0 VRAM byte Screen Pixel (planar) Algorithm to ‘tile’ screen-area // Use Write Mode 0 (“Direct Write”) // Data-Rotate = 0, Function-Select is ‘copy’ // Bit Mask is 0xFF (e.g., all pixels writable) // Enable Set/Reset is 0x7, Set/Reset is 0x1 // pattern-glyph described by array of 8-bytes for (y = ymin; y < ymax; y++) for (x = xmin; x < xmax; x++) vram[ y * 80 + x ] = glyph[ y % 8 ]; Designing bitmap ‘patterns’ • You can create interesting backgrounds • Fill screen regions with a copied pattern 0xFF 0x80 0x80 0x80 0xFF 0x08 0x08 0x08 foreground color background color Algorithm for ‘tiling’ (mode 19) unsigned char pat[ 8 ]; # 8x8 2-color bitmap unsigned char *vram = 0x000A0000, color; for (int y = 0; y < vres; v++) for (int x = 0; x < hres; x++) { int r = y % 8, k = x % 8; color = ( pat[ r ] & (0x80>>k) ) ? fg : bg; vram[ y*hres + x ] = color; } In-class exercise • • • • Take a look at our ‘brickpat.cpp’ demo It tiles the screen with a brick-wall pattern But it executes in mode 19 (256-colors) Can you revise this demo so that it will work in a ‘planar’ mode (i.e., 16-colors)? • Hint: Apply the principles of Write Mode 0 in a manner similar to ‘drawtext.cpp’ demo • Can you write text against your brick-wall?