4 显示字符(harib02d)

内部的处理差不多了,我们还是将重点放回到外部显示上来吧。到昨天为止,我们算是画出了一幅稍微像样的画,今天就来在画面上写字。以前我们显示字符主要靠调用BIOS函数,但这次是32位模式,不能再依赖BIOS了,只能自力更生。

那么怎么显示字符呢?字符可以用8×16的长方形像素点阵来表示。想象一个下图左边的数据,然后按下图右边所示的方法置换成0和1,这个方法好像不错。然后根据这些数据在画面上打上点就肯定能显示出字符了。8“位”是一个字节,而1个字符是16个字节。

大家可能会有各种想法,比如“我觉得8×16的字太小了,想显示得更大一些”、“还是小点儿的字好”等。不过刚开始我们就先这样吧,一上来要求太多的话,就没有办法往前进展了。

■■■■■

像这种描画文字形状的数据称为字体(font)数据,那这种字体数据是怎样写到程序里的呢?有一种临时方案:

static char font_A[16] = {
    0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
    0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
};

其实这仅仅是将刚才的0和1的排列,重写成十六进制数而已。C语言无法用二进制数记录数据,只能写成十六进制或八进制。嗯,读起来真费劲呀。嫌字体不好看,想手动修正一下,都不知道到底需要修改哪儿。但是暂时就先这样吧,以后再考虑这个问题。

数据齐备之后,只要描画到画面上就可以了。用for语句将画8个像素的程序循环16遍,就可以显示出一个字符了。于是我们制作了下面这个函数。

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
    int i;
    char d; /* data */
    for (i = 0; i < 16; i++) {
        d = font[i];
        if ((d & 0x80) ! = 0) { vram[(y + i) * xsize + x + 0] = c; }
        if ((d & 0x40) ! = 0) { vram[(y + i) * xsize + x + 1] = c; }
        if ((d & 0x20) ! = 0) { vram[(y + i) * xsize + x + 2] = c; }
        if ((d & 0x10) ! = 0) { vram[(y + i) * xsize + x + 3] = c; }
        if ((d & 0x08) ! = 0) { vram[(y + i) * xsize + x + 4] = c; }
        if ((d & 0x04) ! = 0) { vram[(y + i) * xsize + x + 5] = c; }
        if ((d & 0x02) ! = 0) { vram[(y + i) * xsize + x + 6] = c; }
        if ((d & 0x01) ! = 0) { vram[(y + i) * xsize + x + 7] = c; }
    }
    return;
}

if语句是第一次登场,我们来介绍一下。if语句先检查“()”内的条件式,当条件成立时,就执行“{}”内的语句,条件不成立时,什么都不做。

&是以前曾出现过的AND(“与”)运算符。0x80也就是二进制数10000000,它与d进行“与”运算的结果如果是0,就说明d的最左边一位是0。反之,如果结果不是0,则d的最左边一位就是1。“! =”是不等于的意思,在其他语言中,有时写作“<>”。

■■■■■

虽然这样也能显示出“A”来,但还是把程序稍微整理一下比较好,因为现在的程序又长运行速度又慢。

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
    int i;
    char *p, d /* data */;
    for (i = 0; i < 16; i++) {
        p = vram + (y + i) * xsize + x;
        d = font[i];
        if ((d & 0x80) ! = 0) { p[0] = c; }
        if ((d & 0x40) ! = 0) { p[1] = c; }
        if ((d & 0x20) ! = 0) { p[2] = c; }
        if ((d & 0x10) ! = 0) { p[3] = c; }
        if ((d & 0x08) ! = 0) { p[4] = c; }
        if ((d & 0x04) ! = 0) { p[5] = c; }
        if ((d & 0x02) ! = 0) { p[6] = c; }
        if ((d & 0x01) ! = 0) { p[7] = c; }
    }
    return;
}

这样就好多了,我们就用这段程序吧。

下面将这段程序嵌入到bootpack.c中进行整理。大家仔细看看,如果顺利的话,能显示出字符“A”。紧张激动的时刻到了,运行“make run”。哦,“A”显示出来了!