30天自制操作系统 杂谈2

Quote

作者: “所谓开发操作系统,就是想办法制作一张‘含有操作系统的,能够自动启动的 磁盘’。
作者:一上来要求太多的话,就没有办法往前进展了。
小恶魔·兰尼斯特:…我们一次只玩一个游戏。

显示字符

由于我们采用的是32位模式,不能依赖BIOS,只能自力更生了。假定采用8x16的像素点阵去表示:
30天自制操作系统 杂谈2
易得字符输出函数:

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
	int i;
	char *p, d;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }    //x80=1000 0000
		if ((d & 0x40) != 0) { p[1] = c; }    //x40=0100 0000 
		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;
}

//主函数内:
static char font_A[16] = {
		0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
		0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
};
putfont8(binfo->vram, binfo->scrnx, 10, 10, COL8_FFFFFF, font_A);

为了能输出其他字符我们用到hankaku.txt,里面还有其他字符的字体数据,且按照ASCLL字符编码。
例如,A的字体数据放在“hankaku+0x41*16"开始的16字节里面。所以我们可以改变主函数的内容。

putfont8(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, hankaku + 'A' * 16);

更进一步,从显示一个字符到显示一个字符串,我们可以写一个函数:

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
	extern char hankaku[4096];
	for (; *s != 0x00; s++) {
		putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
		x += 8;
	}
	return;
}

#当然在Makefile文件生成规则里加上:
hankaku.bin : hankaku.txt Makefile
	$(MAKEFONT) hankaku.txt hankaku.bin

hankaku.obj : hankaku.bin Makefile
	$(BIN2OBJ) hankaku.bin hankaku.obj _hankaku     #实现和其他obj文件编译链接

描绘鼠标指针

既然能显示字符,鼠标指针也不是难事(而且我们可以自行DIY字体和鼠标指针样式)。我们假定用16x16的方阵去表示:

void init_mouse_cursor8(char *mouse, char bc)
{
	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;

	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;
}
//显示背景色
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;
}

init_mouse_cursor8(mcursor, COL8_008484);
putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);

最后附上效果图(变量也是同理输出):
30天自制操作系统 杂谈2

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	char s[40], mcursor[256];
	int mx, my;

	init_gdtidt();
	init_palette();
	init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
	mx = (binfo->scrnx - 16) / 2; 
	my = (binfo->scrny - 28 - 16) / 2;
	init_mouse_cursor8(mcursor, COL8_008484);
	putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
	sprintf(s, "(%d, %d)", mx, my);
	putfonts8_asc(binfo->vram, binfo->scrnx, 6, 1, COL8_000000, "SNNOPY OS"); //阴影效果
    putfonts8_asc(binfo->vram, binfo->scrnx, 5, 0, COL8_FFFFFF, "SNNOPY OS"); 
    putfonts8_asc(binfo->vram, binfo->scrnx, 6, 19, COL8_000000, s);         //阴影效果
	putfonts8_asc(binfo->vram, binfo->scrnx, 5, 18, COL8_FFFFFF, s);
	
	for (;;) {
		io_hlt();
	}
}

这里笔者就给第一个OS取名SNNOPY了,个人觉得阴影效果还是很赞的。当然我们还没有实现鼠标的移动功能,在此之前我们还需要完成分段,中断处理,以后再说吧。