MacOS环境-手写操作系统-09-绘制系统字体 原创

给系统绘制字体

1.简介

如果我们把字体的大小限定在一个8*16的长方形区域,那么我们在这个区域内,将特定位置的像素点设置成黑色,其他点设置成白色,那么我们就可以得到一个白底黑色的字体:

在这里插入图片描述

2.单字体实现

如果我们把8*16区域当做一个二维数组,白色的像素我们用0表示,黑色像素我们用1表示,

那么上图的字符A, 最顶层的一行全是白色,所以用8个0表示,

第二行,8个像素中,中间两个像素设置成黑色,

于是对应的二进制数就是000 11 000, 对应的16进制数就是0x18,

依次类推,这样对整个字符A, 我们就有可以设置一个对应的数组:

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

拿到字体数组后,绘制时,把数组中的每一个数值取出来,看该数值的二进制形式中,哪一位设置成1,那么就给对应的像素赋予黑色,如果设置成0,就给对应的像素设置成白色,代码如下:

void showFont8(char *vram, int xsize, int x, int y, char c, char* font) {
    int i;
    char d;

    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;}
    }

接着 在write_vga_desktop.c的主函数中,在for(;;)死循环前加入一句:

showFont8(vram, xsize, 20, 20, COL8_FFFFFF, fontA);

对其进行一些列的编译、反汇编、汇编、java操作后

编译C文件

i386-elf-gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop_single_char.o write_vga_desktop_single_char.c

反汇编o文件

./objconv -fnasm write_vga_desktop_single_char.o write_vga_desktop_single_char.asm

删除无用部分

修改kernel

%include "write_vga_desktop_single_char.asm"

修改boot(直接放大一点)直接读了20个扇区 肯定够用了

    mov          AL,  20        ; AL 表示要练习读取几个扇区

编译boot

nasm -o boot.bat boot.asm

编译kernel

nasm -o kernel.bat kernel.asm

运行java

Load file boot.bat to floppy with cylinder: 0 and sector:1
Load file kernel.bat to floppy with cylinder: 1 and sector:2
Load file kernel.bat to floppy with cylinder: 1 and sector:3
Load file kernel.bat to floppy with cylinder: 1 and sector:4
Load file kernel.bat to floppy with cylinder: 1 and sector:5
Load file kernel.bat to floppy with cylinder: 1 and sector:6
Load file kernel.bat to floppy with cylinder: 1 and sector:7
Load file kernel.bat to floppy with cylinder: 1 and sector:8
Load file kernel.bat to floppy with cylinder: 1 and sector:9
Load file kernel.bat to floppy with cylinder: 1 and sector:10
Load file kernel.bat to floppy with cylinder: 1 and sector:11
Load file kernel.bat to floppy with cylinder: 1 and sector:12
Load file kernel.bat to floppy with cylinder: 1 and sector:13
Load file kernel.bat to floppy with cylinder: 1 and sector:14

运行:

3.多字体的实现

MakeFont这个java工程 就是原课程老师封装的一个工具

可以直接将项目下的font.txt文件中的字体转换为我们需要的字体文件 生成fontData.inc

(老师的工具是有bug的 我这里帮它修改了修改)

大家也修改一下MakeFont.java

for (int i = 0; i < 8; i++) {
	if (lineText.charAt(i) == '*') {
		b |= (1 << (8 - i - 1)); // 这里是 8 - i - 1 之前老师写的是: 8 - i (会导致字体显示不全)
	}
}

文件局部(fontData.inc)编译这个字体的时候 记得把原来的删掉 不然可能会追加 导致错误:

systemFont:
db 00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H ,00H
db 00H ,00H ,070H ,088H ,04H ,054H ,054H ,04H ,04H ,054H ,024H ,088H ,070H ,00H ,00H ,00H
db 00H ,00H ,070H ,0f8H ,0fcH ,0acH ,0acH ,0fcH ,0fcH ,0acH ,0dcH ,0f8H ,070H ,00H ,00H ,00H
db 00H ,00H ,00H ,00H ,0d8H ,0fcH ,0fcH ,0fcH ,0f8H ,070H ,020H ,00H ,00H ,00H ,00H ,00H
db 00H ,00H ,00H ,00H ,020H ,070H ,0f8H ,0fcH ,0f8H ,070H ,020H ,00H ,00H ,00H ,00H ,00H
db 00H ,00H ,00H ,00H ,020H ,070H ,0a8H ,0fcH ,0a8H ,020H ,070H ,00H ,00H ,00H ,00H ,00H
db 00H ,00H ,00H ,00H ,020H ,070H ,0f8H ,0fcH ,0acH ,020H ,070H ,00H ,00H ,00H ,00H ,00H
db 00H ,00H ,00H ,00H ,00H ,00H ,030H ,078H ,078H ,030H ,00H ,00H ,00H ,00H ,00H ,00H

有了上面的字体二进制文件后,我们直接将它include到内核文件kernel.asm里

然后在我们的C语言程序中直接使用即可

在C语言中我们先声明一个外部变量数组:

extern char systemFont[16]

比如要绘制代码如下:

extern char systemFont[16];

void showFont8(char *vram, int xsize, int x, int y, char c, char* font);

void CMain(void) {
    struct BOOTINFO bootInfo;
    initBootInfo(&bootInfo);
    char*vram = bootInfo.vgaRam;
    int xsize = bootInfo.screenX, ysize = bootInfo.screenY;

    init_palette();

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

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

    boxfill8(vram, xsize, COL8_848484, xsize-47, ysize-24, xsize-4, ysize-24);
    boxfill8(vram, xsize, COL8_848484, xsize-47, ysize-23, xsize-47, ysize-4);
    boxfill8(vram, xsize, COL8_FFFFFF, xsize-47, ysize-3, xsize-4, ysize-3);
    boxfill8(vram, xsize, COL8_FFFFFF, xsize-3,  ysize-24, xsize-3, ysize-3);

    showFont8(vram, xsize, 8, 8, COL8_FFFFFF, systemFont + 'A'*16);
    showFont8(vram, xsize, 16, 8, COL8_FFFFFF, systemFont + 'B'*16);
    showFont8(vram, xsize, 24, 8, COL8_FFFFFF, systemFont + 'C'*16);
    showFont8(vram, xsize, 32, 8, COL8_FFFFFF, systemFont + '1'*16);
    showFont8(vram, xsize, 48, 8, COL8_FFFFFF, systemFont + '2'*16);
    showFont8(vram, xsize, 64, 8, COL8_FFFFFF, systemFont + '3'*16);

    for(;;) {
       io_hlt();
    }

}

再按照上边的流程走一遍:

编译C文件

i386-elf-gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop_systemFont.o write_vga_desktop_systemFont.c

反汇编o文件

./objconv -fnasm write_vga_desktop_systemFont.o write_vga_desktop_systemFont.asm

删除无用部分

修改kernel

%include "write_vga_desktop_systemFont.asm"

修改boot(直接放大一点)直接读了20个扇区 肯定够用了

    mov          AL,  20        ; AL 表示要练习读取几个扇区

编译boot

nasm -o boot.bat boot.asm

编译kernel

nasm -o kernel.bat kernel.asm

运行java 生成system.img

运行

在这里插入图片描述

4.显示字符串

我们能够显示单个字符,只要稍加加工,我们就可以显示一个字符串,显示字符串只不过是将字符连在一起显示罢了,具体代码如下:

void showString(char* vram, int xsize, int x, int y, char color, unsigned char *s ) {
    for (; *s != 0x00; s++) {
       showFont8(vram, xsize, x, y,color, systemFont+ *s * 16);
       x += 8;
    }
}

再再再走一遍流程:

编译C文件

i386-elf-gcc -m32 -fno-asynchronous-unwind-tables -s -c -o write_vga_desktop_string.o write_vga_desktop_string.c

反汇编o文件

./objconv -fnasm write_vga_desktop_string.o write_vga_desktop_string.asm

删除无用部分

修改kernel

%include "write_vga_desktop_string.asm"

修改boot(直接放大一点)直接读了20个扇区 肯定够用了

    mov          AL,  20        ; AL 表示要练习读取几个扇区

编译boot

nasm -o boot.bat boot.asm

编译kernel

nasm -o kernel.bat kernel.asm

运行java 生成system.img

posted @   武子康  阅读(0)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示