haribote graphic.c 由像素点阵转换显卡画面信息程序阅读注释

Posted 资质平庸的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了haribote graphic.c 由像素点阵转换显卡画面信息程序阅读注释相关的知识,希望对你有一定的参考价值。

[ 1] haribote ipl09.nas 引导程序阅读注释
[ 2] haribote asmhead.nas 从实模式进入保护模式程序阅读注释
[ 3] haribote dsctbl.c 设置GDT和IDT程序阅读注释
[ 4] haribote memory.c 内存管理程序阅读注释
[ 5] haribote int.c 可编程中断控制器(PIC)初始配置程序阅读注释
[ 6] haribote timer.c 定时器管理程序阅读注释
[ 7] haribote fifo.c 循环队列管理程序阅读注释
[ 8] haribote keyboard.c 键盘管理程序阅读注释
[ 9] haribote mouse.c 鼠标管理程序阅读注释

篇幅较长,可通过浏览器的搜索功能(Ctrl + f)搜索函数名了解相应函数的实现机制,如 init_palette。

[10] haribote graphic.c 由像素点阵转换显卡画面信息程序阅读注释

/* 单从接口上看,graphic.c中的接口有 无参数检查的缺陷。
 * 
 * 回看之前所粗略阅读的程序接口, 他们都没有涉及参数合
 * 理性的检查。作者可能是为了减少接口代码量和提升程序
 * 性能(省CPU分支预测错误风险), 再加上无他人懵懂调用,
 * 所以免去了参数检查部分代码。
 *
 * 不过,graphic.c中的形参名vram真够具迷惑性的......尤
 * 其是在还没有阅读sheet.c,window.c以及bootpack.c的情
 * 况下。摊开这些小缺点, haribote仍旧是此文心中优秀的
 * 高综合性程序作品。*/
graphic.c
/* graphic.c, 将像素点阵转换为显存中的画面信息(调色板色号)的程序接口 */

#include "bootpack.h"

/* 粗略理解DAC调色板,显存内存地址空间和屏幕像素点坐标对应关系。
 * 
 * 在asmhead.nas中通过VBE设置的SuperVGA显示模式(1024 x 768 x 8)支持DAC调色板。
 * 1024和768分别表示显卡在横向和纵向所支持的像素点数,8表示每个像素点支持8位色
 * (256种颜色)。依靠调色板,一种RGB颜色可用调色板号(色号)来指定。
 * PLT_nr    RGB_color
 *       |--------------|
 *   0   | R0 | G0 | B0 |
 *       |--------------|
 *   1   | R1 | G1 | B1 |
 *       |--------------|
 *  ...  | .. | .. | .. |
 *       |--------------|
 *  255  |R255|G255|B255|
 *       |--------------|
 * 往调色板中设定RGB颜色后,可用调色板中的色号指定RGB,如色号0将指定RGB
 * "R0G0B0".
 * 
 * 往1字节显存中写入色号nr,该字节显存所对应的屏幕像素点就会呈现色号
 * nr对应的RGB_color颜色。
 * |==========================================================|
 * |   |----|       ----------------------------------------- |
 * |   |----|       |(0,0)    | (0,1)  |(...) |(0, 767)     | |
 * |   |----|       |---------------------------------------| |
 * |   |----|       |(1,0)    | (1,1)  |(...) |(1, 767)     | |
 * |   |----|       |---------------------------------------| |
 * |   |----|       |(...,0)  | (...,1)|(m,k) |(..., 767)   | |
 * |   |----|       |---------------------------------------| |
 * |   |----|       |(1023,0) | (1023,1) |(...) |(1023, 767)| |
 * |   |----|       ----------------------------------------- |
 * |vram addr space                screen                     |
 * |==========================================================|
 * 屏幕像素点(m,k)对应的显存地址为 vram_base_addr + k * 1024 + m.
 * 通过使用调色板,可以通过一字节显存指定屏幕像素点的RGB颜色。*/


/* 关于像素点阵的表示。
 * 
 * 往显存地址(vram_base_addr + y * xsize + x)写入颜色号cr,
 * 屏幕(x,y)处像素点会呈色号cr对应RGB颜色。若需在屏幕(x,y)
 * 像素点处以色号cr开始显示字符'A'
 * |——————————————————————|
 * |    (x,y)             |
 * |      ........        |
 * |      ...**...        |
 * |      ...**...        |
 * |      ...**...        |
 * |      ...**...        |
 * |      ..*..*..        |
 * |      ..*..*..        |
 * |      ..*..*..        |
 * |      ..*..*..        |
 * |      .******.        |
 * |      .*....*.        |
 * |      .*....*.        |
 * |      .*....*.        |
 * |      ***..***        |
 * |      ........        |
 * |      ........        |
 * |______________________| (假设屏幕就这么大^_^)
 * 
 * 则应往屏幕上'*'对应显存中写入色号cr即可显示'A'(cr与屏幕背景色号不同)。
 * 
 * 可用如下C程序实现该功能:
 * char font[16 * 8 + 1] = 
 *     "........"
 *     "...**..."
 *     "...**..."
 *     "...**..."
 *     "...**..."
 *     "..*..*.."
 *     "..*..*.."
 *     "..*..*.."
 *     "..*..*.."
 *     ".******."
 *     ".*....*."
 *     ".*....*."
 *     ".*....*."
 *     "***..***"
 *     "........"
 *     "........"
 * ;
 * for (r = 0; r < 16; ++r)
 *     for (c = 0; c < 8; ++c)
 *         if (font[r * 8 + c] == '*')
 *             vaddr[(y + r) * xsize + x + c] = cr;
 * 如此,显存中就包含了起始于屏幕(x,y)像素点处的字符'A'画面信息(色号),
 * 即实现在屏幕(x,y)像素点处开始以cr色号对应RGB显示字符'A'。
 * 
 * 若需节约内存,可用二进制位表示字符'A'的像素点阵。
 * "........" -> 0 0 0 0 0 0 0 0 -> 0x00
 * "...**..." -> 0 0 0 1 1 0 0 0 -> 0x18
 * "...**..." -> 0 0 0 1 1 0 0 0 -> 0x18
 * "...**..." -> 0 0 0 1 1 0 0 0 -> 0x18
 * "...**..." -> 0 0 0 1 1 0 0 0 -> 0x18
 * "..*..*.." -> 0 0 1 0 0 1 0 0 -> 0x24
 * "..*..*.." -> 0 0 1 0 0 1 0 0 -> 0x24
 * "..*..*.." -> 0 0 1 0 0 1 0 0 -> 0x24
 * "..*..*.." -> 0 0 1 0 0 1 0 0 -> 0x24
 * ".******." -> 0 1 1 1 1 1 1 0 -> 0x7e
 * ".*....*." -> 0 1 0 0 0 0 1 0 -> 0x42
 * ".*....*." -> 0 1 0 0 0 0 1 0 -> 0x42
 * ".*....*." -> 0 1 0 0 0 0 1 0 -> 0x42
 * "***..***" -> 1 1 1 0 0 1 1 1 -> 0xe7
 * "........" -> 0 0 0 0 0 0 0 0 -> 0x00
 * "........" -> 0 0 0 0 0 0 0 0 -> 0x00
 * 
 * 如此,实现在屏幕(x,y)像素点处显示'A'的C程序可变为
 * char font[16] = 
 *     0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24
 *     0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00
 * ;
 * for (r = 0; r < 16; ++r)
 *     if (font[r] & 0x80)
 *         vram[(y + r) * xsize + 0] = cl;
 *     if (font[r] & 0x40)
 *         vram[(y + r) * xsize + 1] = cl; *     
 *     // ...to check every bit of the current byte...
 *
 *     if (font[r] & 0x01)
 *         vram[(y + r) * xsize + 7] = cl;
 *
 * 两个程序往显存中写入的画面信息是相同的,后者节约了内存, 按照16*8的像素点阵来算,
 * 后者在一个字符中能节约(16 * 8 + 1) - 16 = 113个字节。字库中各字符的像素点阵就
 * 是采用的二进制信息表示方法。在使用字库时,需要用字符编码值去字库中索引其像素点阵。*/



/* init_palette,
 * 为DAC调色板指定RGB颜色。*/
void init_palette(void)

    /* 抽取16种基础RGB颜色(可以不用static修饰) */
    static unsigned char table_rgb[16 * 3] = 
        /*Red,Green,Blue*/
        0x00, 0x00, 0x00, /*  0:黑色 */
        0xff, 0x00, 0x00, /*  1:红色 */
        0x00, 0xff, 0x00, /*  2:绿色 */
        0xff, 0xff, 0x00, /*  3:黄色 */
        0x00, 0x00, 0xff, /*  4:蓝色 */
        0xff, 0x00, 0xff, /*  5:紫红 */
        0x00, 0xff, 0xff, /*  6:青色 */
        0xff, 0xff, 0xff, /*  7:白色 */
        0xc6, 0xc6, 0xc6, /*  8:亮灰 */
        0x84, 0x00, 0x00, /*  9:暗红 */
        0x00, 0x84, 0x00, /* 10:暗绿 */
        0x84, 0x84, 0x00, /* 11:暗黄 */
        0x00, 0x00, 0x84, /* 12:暗蓝 */
        0x84, 0x00, 0x84, /* 13:暗紫 */
        0x00, 0x84, 0x84, /* 14:暗白 */
        0x84, 0x84, 0x84  /* 15:暗灰 */
    ;
    /* 指定调色板前16种颜色;0-黑色,... */
    set_palette(0, 15, table_rgb);

    /* 将RGB中的每种颜色都划分成6个色阶即6等份[0, 1*51,..., 5*51],
     * 然后依次将他们设置在色号[16,231]中。如此又得到216种RGB所描
     * 述的颜色, 加上调色板中前16种基础色,现调色板中一共有232种RGB颜色。*/
    unsigned char table2[216 * 3];
    int r, g, b;
    for (b = 0; b < 6; b++) 
        for (g = 0; g < 6; g++) 
            for (r = 0; r < 6; r++) 
                table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51;
                table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51;
                table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51;
            
        
    
    set_palette(16, 231, table2);
    return;


/* set_palette,
 * 用rgb所指内存中包含的RGB颜色依次设置在调色板号[start, end]中。*/
void set_palette(int start, int end, unsigned char *rgb)

    int i, eflags;

    /* 备份EFLAG到eflags变量中,然后设置EFLAG禁止CPU处理本进程中断 */
    eflags = io_load_eflags();
    io_cli();

    /* 将起始调色板号写入调色板3c8h端口, 然后将每一组rgb依次写入调色板
     * 3c9h端口即完成一次调色板号的设置,除以4只是将RGB颜色变浅/深了一点。*/
    io_out8(0x03c8, start);
    for (i = start; i <= end; i++) 
        io_out8(0x03c9, rgb[0] / 4);
        io_out8(0x03c9, rgb[1] / 4);
        io_out8(0x03c9, rgb[2] / 4);
        rgb += 3;
    
    /* 恢复EFLAG允许CPU处理当前进程中断 */
    io_store_eflags(eflags);
    return;


/* boxfill8,
 * 用色号c充当窗口[(x0,y0),(x1,y1)]区域画面信息,窗口x方向像素点数为xsize。
 * |===========================|
 * | (x0,y0)|-------|          |
 * |        |ccccccc|          |
 * |        |-------|(x1,y1)   |
 * |                           |
 * |===========================|
 * |<-----window xsize-------->|
 * 
 * vram, 用于缓存窗口的画面信息;
 * [(x0,y0),(x1,y1)], 基于窗口左上角的窗口区域;
 * c, 填充窗口[(x0,y0),(x1,y1)]区域的色号。
 *
 * 当vram为显存基址,xsize为屏幕x箱数点时,屏幕[(x0,y0),(x1,y1)]区域将会直接显示色号c对应的RGB颜色。*/
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)

    int x, y;

    /* 将色号c写入窗口像素(x,y)处所对应缓存中 */
    for (y = y0; y <= y1; y++) 
        for (x = x0; x <= x1; x++)
            vram[y * xsize + x] = c;
    
    return;


/* init_screen8,
 * 将自制屏幕背景窗口画面信息缓存到vram所指内存中。
 * x,y分别为屏幕横向(x)和纵向(y)的像素点数。*/
void init_screen8(char *vram, int x, int y)

    boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
    boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
    boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
    boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

    boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
    boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
    boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
    boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
    boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
    boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

    boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
    boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
    boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
    boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);

/* 自制屏幕背景窗口画面大体如下(每个十六进制数代表像素点的色号,':'表像素点省略部分)。
 * |——————————————————————————————————————————————————————————————————|
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE |
 * |88888888888888888888888888888888888888888888888888888888888888888 |
 * |77777777777777777777777777777777777777777777777777777777777777777 |
 * |8FFFFFFFFFF08888888888888888888888888888888888888FFFFFFFFF7888888 |
 * |8FFFFFFFFFF08888888888888888888888888888888888888FFFFFFFFF7888888 |
 * |8FFFFFFFFFF08888888888888888888888888888888888888FFFFFFFFF7888888 |
 * |80000000000088888888888888888888888888888888888887777777777888888 |
 * |88888888888888888888888888888888888888888888888888888888888888888 |
 * |                                                                  |
 * |——————————————————————————————————————————————————————————————————| */

    return;


/* putfont8,
 * 将font所指像素点阵用c充当画面信息,
 * 并将画面信息从vram所指画面的(x,y)像素点位置处开始缓存。
 * 
 * font所指向的16字节是一个字符的像素点阵。
 * 如字符'A'的像素点阵
 * 0 0 0 0 0 0 0 0 -> 0x00
 * 0 0 0 1 1 0 0 0 -> 0x18
 * 0 0 0 1 1 0 0 0 -> 0x18
 * 0 0 0 1 1 0 0 0 -> 0x18
 * 0 0 0 1 1 0 0 0 -> 0x18
 * 0 0 1 0 0 1 0 0 -> 0x24
 * 0 0 1 0 0 1 0 0 -> 0x24
 * 0 0 1 0 0 1 0 0 -> 0x24
 * 0 0 1 0 0 1 0 0 -> 0x24
 * 0 1 1 1 1 1 1 0 -> 0x7e
 * 0 1 0 0 0 0 1 0 -> 0x42
 * 0 1 0 0 0 0 1 0 -> 0x42
 * 0 1 0 0 0 0 1 0 -> 0x42
 * 1 1 1 0 0 1 1 1 -> 0xe7
 * 0 0 0 0 0 0 0 0 -> 0x00
 * 0 0 0 0 0 0 0 0 -> 0x00
 * 即font中的内容为
 * char font[] = 
 *      0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24,
 *      0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00
 * ;
 * 
 * putfont8依次遍历font中的每一位,当遍历到bit位为1时,
 * 则将指定颜色号c写入vram所指内存的对应字节上。*/
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;


/* putfonts8_asc,
 * 按照当前进程的语言模式(英文,日文等),根据s所指字符编码值
 * 从相应字库中取出字符的像素点阵, 将其转换为画面信息并从
 * vram所指画面(x,y)像素点处开始缓存;直到s所指字符编码值为
 * 0时结束。
 *
 * 如'A'编码值 --> 字符'A'在字库中像素点阵
 * 65  --------->  0x00    0 0 0 0 0 0 0 0
 *                 0x18    0 0 0 1 1 0 0 0
 *                 0x18    0 0 0 1 1 0 0 0
 *                 0x18    0 0 0 1 1 0 0 0
 *                 0x18    0 0 0 1 1 0 0 0
 *                 0x24    0 0 1 0 0 1 0 0
 *                 0x24    0 0 1 0 0 1 0 0
 *                 0x24    0 0 1 0 0 1 0 0
 *                 0x24    0 0 1 0 0 1 0 0
 *                 0x7e    0 1 1 1 1 1 1 0
 *                 0x42    0 1 0 0 0 0 1 0
 *                 0x42    0 1 0 0 0 0 1 0
 *                 0x42    0 1 0 0 0 0 1 0
 *                 0xe7    1 1 1 0 0 1 1 1
 *                 0x00    0 0 0 0 0 0 0 0
 *                 0x00    0 0 0 0 0 0 0 0
 * 首先根据字符编码在字库中找到字符的像素点阵,然后根据字符像素点阵得到字符
 * 画面信息(色号c),最后将字符画面信息从vram所指画面(x,y)像素点处开始缓存。*/
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)

    /* hankaku是hankaku.txt中各符号像素点阵开始处标号(_hankaku)。由于hankaku.txt中只有
     * 256个英文字符,其对应的像素点阵所占内存比较小(256 x 16 bytes),所以该部分像素点阵
     * 被链接到haribote.sys中成为操作系统的一部分。欲在程序中使用hankaku.txt中字符的像
     * 素点阵时,先将hankaku当做全局变量标识符先声明一下,再根据字符编码值索引其像素点阵。*/
    extern char hankaku[4096];
    /* 当程序运行到此处时,所获取到任务结构体为管理当前程序任务的结构体 */
    struct TASK *task = task_now();

    /* 内存地址0xfe8处存储了 nihongo.fnt 字库文件在内存中的基址(见HariMain)。FAT12映像
     * 软盘除了包含haribote.sys操作系统程序文件外,还包含一些其他文件,如字库文件,应用程
     * 序文件等。字库文件nihongo由操作系统启动后从FAT12映像盘的缓冲区读入,内存段
     * [100000h, 267fffh]缓存了映像软盘内容(见asmhead.nas)。*/
    char *nihongo = (char *) *((int *) 0x0fe8), *font;
    int k, t;

/* 从字符库中获取s所指字符(编码值)的像素点阵信息,并将其画面信息缓存在vram所指画面的
 * (x,y)像素点处。如果不关心字符像素点阵在字符库中的组织方式(编码方式),可略过计算各
 * 字符像素点阵信息在字符库中位置的代码,如字符面,区,点的计算。*/

    /* 从英文字库中获取s所指字符的像素点阵,
     * 并将其对应的画面信息缓存在vram所指画面的(x,y)像素点位置处 */
    if (task->langmode == 0) 
        /* hankaku按照字符编码值[0, 255]升序顺序依次包含了各字符的像素点阵。
         * 因为每个字符像素点阵占16字节,所以(*s * 16)得到字符(*s)在hankaku
         * 内存段中的像素点阵。putfont8将(*s)像素点阵的画面信息存于vram所指
         * 画面的(x,y)像素点位置处。*/
        for (; *s != 0x00; s++) 
            putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
            x += 8;
        
    

/* 日文字符(文字)分半角字符和全角字符,半角字符指其像素点阵为16 x 8,其字符编码值
 * 范围为[0x00,0x7f],其编码值可直接作为字符在字符库中像素点阵的索引(同hankaku);
 * 全角字符指其像素点阵信息为16 x 16,其字符编码值占2字节,这两字节以面,区,点定位
 * 字符像素点阵在字符库中的位置,第一个字节编码值用于描述字符像素点阵在字符库中的
 * 面和区,第二字节编码值用于描述字符像素点阵在字符库中的区和点。*/

    /* 获取s所指字符在日文字库中的画面信息 */
    if (task->langmode == 1) 
        for (; *s != 0x00; s++) 
            /* langbyte1=0: 刚解析完上一个字符编码或还未处理当前字符编码 */
            if (task->langbyte1 == 0) 
                /* 根据第1字节编码判断该字符为全角字符 */
                if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) 
                    task->langbyte1 = *s; /* 记录全角字符像素点阵的面和区 */

                /* 根据半角字符编码值在字库中索引到像素点阵,
                 * 将其转换为画面信息存于vram所指画面的(x,y像素点处) */
                 else 
                    putfont8(vram, xsize, x, y, c, nihongo + *s * 16);
                
             else  /* 全角字符第2字节编码 */
                /* 根据记录在langbyte1中的第1字节编码值计算字符像素点阵的面和区号 */
                if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f)  /* 1面 */
                    k = (task->langbyte1 - 0x81) * 2; /* k=1面中区号 */
                 else /* 2面 */
                    k = (task->langbyte1 - 0xe0) * 2 + 62; /* k=2面中区号 */
                
                /* 根据字符第2字节编码值计算字符像素点阵所在区的点号 */
                if (0x40 <= *s && *s <= 0x7e) 
                    t = *s - 0x40;
                 else if (0x80 <= *s && *s <= 0x9e) 
                    t = *s - 0x80 + 63;
                 else 
                    t = *s - 0x9f;
                    k++; /* 较大区号 */
                
                /* 获取到1个全角字符像素点阵面区点信息后复位0 */
                task->langbyte1 = 0;
                
                /* 256 * 16 为半角字符像素点阵在字库中所占字节数;
                 * k为全角字符像素点阵区号,每个区共有94个全角字符,
                 * t为全角字符像素点阵在k区中的点号,字库前面字符像
                 * 素点阵所占字节数为(k * 94 + t) * 32。font最终指
                 * 向当前字符在字库中的像素点阵。*/
                font = nihongo + 256 * 16 + (k * 94 + t) * 32;
                putfont8(vram, xsize, x - 8, y, c, font     );
                putfont8(vram, xsize, x    , y, c, font + 16);
            
            /* 当获取一个半角字符的像素点阵后,x方向像素点将增长8个像素点,
             * 当获取一个全角字符的像素点阵号,由于全角字符有两个字节编码
             * 值,所以该语句会被执行两次即x方向像素点会增长16个像素点。*/
            x += 8;
        
    

    /* s所指字符在日文EUC模式下的画面信息 */
    if (task->langmode == 2) 
        for (; *s != 0x00; s++) 
            if (task->langbyte1 == 0)  /* 已处理全角或半角字符编码值 */
                if (0x81 <= *s && *s <= 0xfe) 
                    task->langbyte1 = *s; /* 记录全角字符第1编码值 */
                 else  /* 获取半角字符像素点阵并写入vram显示 */
                    putfont8(vram, xsize, x, y, c, nihongo + *s * 16);
                
             else  /* 处理全角字符第2编码字节 */
                /* 计算全角字符像素点阵的区号和点号 */
                k = task->langbyte1 - 0xa1;
                t = *s - 0xa1;
                task->langbyte1 = 0; /* 已获取全角字符像素点阵 */

                /* 根据全角字符的像素点阵将其对应的画面
                 * 信息写入vram所指画面的(x,y)像素点处。*/
                font = nihongo + 256 * 16 + (k * 94 + t) * 32;
                putfont8(vram, xsize, x - 8, y, c, font     );
                putfont8(vram, xsize, x    , y, c, font + 16);
            
            x += 8;
        
    
    return;

/* 结合本文件开始处的粗略知识,粗略理解hankaku.txt中各字符图标
 * 被工具软件(makefont.exe)转换为像素点阵并组合成字符库过程。
 * (nihongo.fnt字库原理同hankaku)。
 * 
 * char 0x41
 * ........                   0 0 0 0 0 0 0 0     0x00
 * ...**...                   0 0 0 1 1 0 0 0     0x18
 * ...**...                   0 0 0 1 1 0 0 0     0x18
 * ...**...                   0 0 0 1 1 0 0 0     0x18
 * ...**...   makefont.ext    0 0 0 1 1 0 0 0     0x18
 * ..*..*.. --------------->  0 0 1 0 0 1 0 0     0x24
 * ..*..*..                   0 0 1 0 0 1 0 0     0x24
 * ..*..*..                   0 0 1 0 0 1 0 0     0x24
 * ..*..*..                   0 0 1 0 0 1 0 0     0x24
 * .******.                   0 1 1 1 1 1 1 0     0x7e
 * .*....*.                   0 1 0 0 0 0 1 0     0x42
 * .*....*.                   0 1 0 0 0 0 1 0     0x42
 * .*....*.                   0 1 0 0 0 0 1 0     0x42
 * ***..***                   1 1 1 0 0 1 1 1     0xe7
 * ........                   0 0 0 0 0 0 0 0     0x00
 * ........                   0 0 0 0 0 0 0 0     0x00
 * hankaku.txt--------------->(16 * 8bit)像素点阵
 * 在得到字符像素点阵后,调用putfont8即可将字符A显示vram
 * 所指画面(x,y)像素点处。'A'编码值0x41用于在hankaku字库
 * 中索引其像素点阵。*/


/* init_mouse_cursor8,
 * 将鼠标画面信息(色号)缓存在mouse所指内存段中,
 * bc为鼠标所在背景的背景色号。*/
void init_mouse_cursor8(char *mouse, char bc)

    /* 鼠标像素点阵将为16(行) x 16(列), 这里可不用static */
    static char cursor[16][16] = 
        "**************..",
        "*OOOOOOOOOOO*...",
        "*OOOOOOOOOO*....",
        "*OOOOOOOOO*.....",
        "*OOOOOOOO*......",
        "*OOOOOOO*.......",
        "*OOOOOOO*.......",
        "*OOOOOOOO*......",
        "*OOOO**OOO*.....",
        "*OOO*..*OOO*....",
        "*OO*....*OOO*...",
        "*O*......*OOO*..",
        "**........*OOO*.",
        "*..........*OOO*",
        "............*OO*",
        ".............***"
    ;
    int x, y;

    /* 鼠标边缘(*部分)使用偏黑色的色号,
     * 鼠标形状(O部分)使用偏白色的色号,
     * 鼠标剩余部分(.部分)使用背景色号。*/
    for (y = 0; y < 16; y++) 
        for (x = 0; x < 16; x++) 
            if (cursor[y][x] == '*') 
                mouse[y * 16 + x] = COL8_000000;
            
            if (cursor[y][x] == 'O') 
                mouse[y * 16 + x] = COL8_FFFFFF;
            
            if (cursor[y][x] == '.') 
                mouse[y * 16 + x] = bc;
            
        
    
    return;


/* putblock8_8,
 * 将buf所指内存段中的画面信息(如鼠标图标的色号)
 * 缓存在vram所指画面的[(px0, py0),(px0+pxsize, py0+pysize)]区域。*/
void putblock8_8(char *vram, int vxsize, int pxsize,
    int pysize, int px0, int py0, char *buf, int bxsize)

    int x, y;
    for (y = 0; y < pysize; y++) 
        for (x = 0; x < pxsize; x++) 
            vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
        
    
    return;

bootpack.h
/* ... */

/* graphic.c */
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen8(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
void init_mouse_cursor8(char *mouse, char bc);
void putblock8_8(char *vram, int vxsize, int pxsize,
    int pysize, int px0, int py0, char *buf, int bxsize);

/* 调色板前16个调色板号,各调色板
 * 号对应RGB颜色见init_palette中的table_rgb数组。*/
#define COL8_000000 0
#define COL8_FF0000 1
#define COL8_00FF00 2
#define COL8_FFFF00 3
#define COL8_0000FF 4
#define COL8_FF00FF 5
#define COL8_00FFFF 6
#define COL8_FFFFFF 7
#define COL8_C6C6C6 8
#define COL8_840000 9
#define COL8_008400 10
#define COL8_848400 11
#define COL8_000084 12
#define COL8_840084 13
#define COL8_008484 14
#define COL8_848484 15

/* ... */

以上是关于haribote graphic.c 由像素点阵转换显卡画面信息程序阅读注释的主要内容,如果未能解决你的问题,请参考以下文章

基准线

haribote&&linux0.11内存地址转换笔记整理抽取

前端开发与图片处理

最大黑区域

Arduino UNO+ MAX7219驱动8X8点阵显示+Proteus仿真

JPGPNGGIFSVG 等格式图片区别