Drawing In Protected Mode: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
m Added GOP links
m drawing text is better explained on VGA Fonts page
Line 172:
 
== Drawing Text ==
{{Main|VGA Fonts}}
 
Once in graphic mode, you no longer have the BIOS or the hardware to draw fonts for you. The basic idea is to have font data for each character and use it to plot (or not to plot) pixels. There are plenty of ways to store those fonts depending on whether they have multiple colors or not, alpha channel or not etc. What you will basically have, however is:
Line 200 ⟶ 201:
h++;
j = x;
}
}
</source>
=== Font Encoding ===
 
The most common encoding that allows you not to overwrite the background over which you draw your text is the ''font bitmap'', that is, an "A" character will e.g. be encoded as (. is 0 in binary and X is 1)
 
...XX... = 0*128+0*64+0*32+1*16+1*8+0*4+0*2+0*1 = 0x18
..XXXX.. = 0x3C
.XX..XX. = 0x66
.XXXXXX. = 0x7E
.XX..XX. = 0x66
.XX..XX. = 0x66
........ = 0x00
........ = 0x00
 
In which case you test each bit of the font data to tell whether it's 1 or 0 and only put the pixel if it's 1.
For larger fonts you might want to use RLE encoding instead, for instance. Finally, state-of-the-art true-type fonts will require you to support the "freetype" library.
 
=== Optimizations ===
 
Use of a "put_pixel()" function is almost always a performance problem. For an 8 x 8 character you can find out the address of the first (top left) pixel and increment it to get the address of the next pixel in the row, and add the number of bytes per line to get the address of the next row. This is much faster than calculating "address = video_address + y * horizontal_resolution + x" 64 times (per character).
 
However, it's even faster to work on more than one pixel at a time. If you look at the font encoding above you'll notice that there's an 8-bit number for each row of the character. This 8-bit number can be used as the index in a lookup table containing masks. For example, for 8 bits per pixel you could do 8 pixels at a time, like this:
 
<source lang="c">
uint32_t font_data_lookup_table[16] = {
0x00000000,
0x000000FF,
0x0000FF00,
0x0000FFFF,
0x00FF0000,
0x00FF00FF,
0x00FFFF00,
0x00FFFFFF,
0xFF000000,
0xFF0000FF,
0xFF00FF00,
0xFF00FFFF,
0xFFFF0000,
0xFFFF00FF,
0xFFFFFF00,
0xFFFFFFFF
}
 
void draw_char(uint8_t *where, uint32_t character, uint8_t foreground_colour, uint8_t background_colour) {
int row;
uint8_t row_data;
uint32_t mask1, mask2;
uint8_t *font_data_for_char = &system_font_data_address[character * 8];
uint32_t packed_foreground = (foreground << 24) | (foreground << 16) | (foreground << 8) | foreground;
uint32_t packed_background = (background << 24) | (background << 16) | (background << 8) | background;
 
for (row = 0; row < 8; row++) {
row_data = font_data_for_char[row];
mask1 = font_data_lookup_table[row_data / 16];
mask2 = font_data_lookup_table[row_data & 0x0F];
*(uint32_t *)where = (packed_foreground & mask1) | (packed_background & ~mask1);
*(uint32_t *)(&where[4]) = (packed_foreground & mask2) | (packed_background & ~mask2);
where += bytes_per_line;
}
}