VGA Fonts: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (Erm - someone used boolean NOT (!) when they meant bitwise NOT (~). Names suppressed to protect the guilty...)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(13 intermediate revisions by 9 users not shown)
Line 1:
{{TutorialTone}}
So you know how to display characters in text mode, and now you want to do it in graphics mode. It's not complicated, but definitely more complex than writing andan ASCII code at a specific offset in memory. You'll have to do it pixel by pixel.
 
But how do you know what to draw? It's stored in data matrix called bitmap fonts.
Line 25 ⟶ 26:
</pre>
The full bitmap contains bitmaps for every character, thus it's 256*16 bytes, 4096 bytes long. If you want to get the bitmap for a specific character, you have to multiply the ASCII code by 16 (number of rows in a character), add the offset of your bitmap and you're ready to go.
 
A very simple file format to store these is [[PC Screen Font]], used by the Linux Console. It stores fonts the way described above with a small header. Another solution is the [[Scalable Screen Font]] format which comes with an extremely small, free rendering ANSI C library.
 
== How to get fonts? ==
Line 31 ⟶ 34:
Easiest way, but increases your code by 4k. There are several sources that provide the entire font in binary or source format so you do not need to manually write it out.
=== Store it in a file ===
Most modular way. You can use different fonts if you like. Downside you'll need a working filesystem implementation. As for the file format, I'd suggest the aforementioned [[PC Screen Font]] (.psf/.psfu) or [[Scalable Screen Font]] (.sfn).
 
=== Get the copy stored in the VGA BIOS ===
It's a standard BIOS call (no need to check it's persistence). If you're still in real mode, it's quite easy to use.
<sourcesyntaxhighlight lang="asm">
;in: es:di=4k buffer
;out: buffer filled with font
Line 51 ⟶ 55:
rep movsd
pop ds
</syntaxhighlight>
</source>
 
=== Get from VGA RAM directly ===
Maybe you're already in protected mode, so cannot access BIOS functions. In this case you can still get the bitmap by programming VGA registers. Be careful that the VGA always reserves space for 8x32 fonts so you will need to trim off the bottom 16 bytes of each character during the copy:
<sourcesyntaxhighlight lang="asm">
;in: edi=4k buffer
;out: buffer filled with font
Line 70 ⟶ 74:
out dx, ax
;clear even/odd mode (the other way, don't ask why)
mov ax, 0704h0604h
out dx, ax
;copy charmap
Line 86 ⟶ 90:
mov ax, 0302h
out dx, ax
mov ax, 0304h0204h
out dx, ax
mov dx, 03ceh
mov ax, 1005h
out dx, ax
mov ax, 0A06h0E06h
out dx, ax
</syntaxhighlight>
</source>
It worth mentioning that it has to be done '''before''' you switch to VBE graphics mode, because VGA registers are usually not accessible afterwards. This means you won't be able to map the VGA card's font memory to screen memory, and you will read only garbage.
 
Line 108 ⟶ 112:
And finally we came to the point where we can display a character. I'll assume you have a putpixel procedure ready.
We have to draw 8x16 pixels, one for every bit in the bitmap.
<sourcesyntaxhighlight lang="c">
//this is the bitmap font you've loaded
unsigned char *font;
Line 116 ⟶ 120:
int cx,cy;
int mask[8]={1,2,4,8,16,32,64,128};
unsigned char *gylphglyph=font+(int)c*16;
 
for(cy=0;cy<16;cy++){
Line 124 ⟶ 128:
}
}
</syntaxhighlight>
</source>
The arguments are straightforward. You may wonder why to subtract 12 from y. It's for the baseline: you specify y coordinate as the bottom of the character, not counting the "piggy tail" in a glyph that goes down (like in "p","g","q" etc.). I other words it's the most bottom row of letter "A" that has a bit set.
 
Although it's mostly useful to erase the screen under the glyph, in some cases it could be bad (eg.: writing on a shiny gradiented button). So here's a slightly modificated version, that uses a transparent background.
<sourcesyntaxhighlight lang="c">
//this is the bitmap font you've loaded
unsigned char *font;
Line 136 ⟶ 140:
int cx,cy;
int mask[8]={1,2,4,8,16,32,64,128};
unsigned char *gylphglyph=font+(int)c*16;
 
for(cy=0;cy<16;cy++){
Line 144 ⟶ 148:
}
}
</syntaxhighlight>
</source>
As you can see, we have only foreground color this time, and the putpixel call has a condition: only invoked if the according bit in the bitmap is set.
 
Of course the code above will be excruciatingly slow (mostly due to doing one pixel at a time, and repeatedly recalculating the address for each pixel within the "putpixel()" function). For much better performance, the code above can be optimised to use boolean operations and a "mask lookup table" instead. For example (for an 8-bpp mode):
 
<sourcesyntaxhighlight lang="c">
//this is the bitmap font you've loaded
unsigned char *font;
Line 203 ⟶ 207:
}
}
</syntaxhighlight>
</source>
 
In this case the address in display memory is only calculated once (rather than up to 128 times) and 8 pixels are done in parallel (which removes the inner loop completely).
Line 209 ⟶ 213:
The main downside for this approach is that you need a different function for each "bits per pixel", except that 15-bpp and 16-bpp can use the same code. For worst case (32-bpp) the lookup table costs 8 KiB. The lookup table for 32-bpp can be re-used for 24-bpp, and for 4-bpp no lookup table is needed at all. To support all standard bit depths that VBE is capable of; this gives a total of 5 versions of each "draw character" function (4-bpp, 8-bpp, 15-bpp and 16-bpp, 24-bpp, 32-bpp) and 3 lookup tables (8-bpp, 15-bpp and 16-bpp, 24-bpp and 32-bpp) which cost a combined total of 14 KiB of data if you use static tables (rather than dynamically generating the desired lookup table if/when needed).
 
== See Also ==
* [[VGA Hardware]] - if you want to do it on your own
* [[PC Screen Font]] - wiki has a tutorial on how to display them
* [[Scalable Screen Font]] - comes with a small, free ANSI C rendering library
* [[TrueType Fonts]] - a very complex vector font format, partially proprietary
 
== External Links ==
* [http://www.inp.nsk.su./~bolkhov/files/fonts/univga/ UNI-VGA] - A free Unicode VGA font (.bdf)
* [http://sourceforge.net/projects/bdf2c/ bdf2c] - .bdf font to C source converter.
 
[[Category:VGA]] [[Category:Video]]
== See Also ==
[[Category:Video]]
* [[VGA Hardware]]
[[Category:Fonts]]
 
[[Category:VGA]] [[Category:Video]]