|
一、已解决疑点(答案在注释中)
1.设置调色盘时为何rgb数值要除以4?
二、未解决疑点
暂无
三、功能与实现
显存,即video RAM,VARM在内存中可以抽象为一个二维char数组,每个元素对应屏幕上一个像素点,向这个元素中输入一个值,这个像素点就会变为对应颜色,从而组合出图形。
颜色和数值如何对应呢?
我们都知道char只有8位,最多256个数字,如果我们用8位模式,确实只能至多表示256种颜色,而且有一个默认的对应规则,比如0号颜色就是#000000,15号颜色 就是#ffffff,如果想设置自己的UI风格,这个模式显然不够方便。
更加常用的颜色表示方法是24位RGB,用3个8位二进制数分别代表红绿蓝的亮度,从而组合出256^3=2^24种颜色,这就完全够用了。
那么我们怎么把需要24位的颜色存到只有8位的空间呢?答案是自定义映射
比如我们把0x000000 规定为 0号,0xff0000 规定为 1号,以此类推。我们可以自选至多256个颜色,将其编号,形成一一映射关系。这至多256种颜色就构成一个调色盘,我们可以给这个调色盘编号,还可以设置其他许多个调色盘。调色盘编号也是8位,因此理论上我们至多可以从2^24种颜色自行挑选256*256=2^16种颜色并根据我们的需要进行编号,这足够满足我们的需求了。
四、代码及注释(非常详细)
注:注释构成有三个部分:原有注释的汉化,原书作者对代码和相关知识的解释,笔者学习过程中补充的内容
/* 图形处理库 */
#include "bootpack.h"
void init_palette(void) /*初始化调色盘 */
{
static unsigned char table_rgb[16 * 3] = {
/* 24位色彩模式,每个颜色用三个char表示,分别对应RGB(红绿蓝)*/
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:暗灰 */
};
set_palette(0, 15, table_rgb);
return;
/* C语言中的static char语句只能用于数据,相当于汇编中的DB指令 */
}
void set_palette(int start, int end, unsigned char *rgb)
/* 作用:设置调色盘
参数解释:start:调色盘编号,同时也是本调色盘第一个颜色的编号 ; end:本调色盘最后一个颜色的编号 ; rgb:本调色盘RGB信息的地址*/
{
int i, eflags;
eflags = io_load_eflags(); /* 记录中断许可标志的值*/
io_cli(); /* 将中断许可标志置为0,禁止中断 */
io_out8(0x03c8, start); /*将调色板编号写入0x03c8端口 */
for (i = start; i <= end; i++) { /*一个颜色的信息分3次写入0x03c9端口,每次分别写入一个颜色的RGB */
io_out8(0x03c9, rgb[0] / 4);
io_out8(0x03c9, rgb[1] / 4);
io_out8(0x03c9, rgb[2] / 4);
/* 除以4的解释:硬件规定,
具体来说 :RGB每个分量用一个数据寄存器(8bit, R/W) bit0-7:
但RGB只能在0 ~ 63范围,也就是0~5位,写入读出时将前2位视为0
因此除以4来让前两位置0 */
rgb += 3; /* rgb指向下一个元素 */
}
io_store_eflags(eflags); /* 复原中断许可标志 */
return;
}
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
/* 作用:画一个长方形,
参数解释:vram:显存起始地址;xsize:显存数组列数 ;c:color颜色编号;x0y0:所画长方形起始位置;x1y1:终止位置*/
{
int x, y;
for (y = y0; y <= y1; y++) {
for (x = x0; x <= x1; x++)
vram[y * xsize + x] = c;
}
return;
}
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);
return;
}
void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
/* 作用:在屏幕上打印一个字符(16*16),按字符信息(hankaku.txt文件中的字体格式)
参数解释:vram:显存起始地址;xsize:显存每一行的像素数,即数组列数; xy:起始位置; c:颜色;
font:字符信息,格式: hankaku + &#39;字符&#39; * 16
*/
{
int i;
char *p; /* 每一行像素点的起始位置 */
char d; /* data */;
for (i = 0; i < 16; i++) { /*每次循环画出一行,一共画出16行 */
p = vram + (y + i) * xsize + x;
d = font;
if ((d & 0x80) != 0) { p[0] = c; } /*第i行第1格 */
if ((d & 0x40) != 0) { p[1] = c; } /*第i行第2格 */
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;
}
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
/* 作用:在屏幕上打印字符串,按ascii码(本函数是对putfont8的进一步封装)
参数解释:vram:显存起始地址;xsize:显存数组列数; xy:起始位置; c:颜色; s:字符串地址*/
{
extern char hankaku[4096];
for (; *s != 0x00; s++) {
putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
x += 8;
}
return;
}
void init_mouse_cursor8(char *mouse, char bc)
/* 作用:准备鼠标指针(16×16)
参数解释:mouse:鼠标信息数组位置(传入传出参数), bc:back-color 背景色*/
{
static char cursor[16][16] = {
&#34;**************..&#34;,
&#34;*OOOOOOOOOOO*...&#34;,
&#34;*OOOOOOOOOO*....&#34;,
&#34;*OOOOOOOOO*.....&#34;,
&#34;*OOOOOOOO*......&#34;,
&#34;*OOOOOOO*.......&#34;,
&#34;*OOOOOOO*.......&#34;,
&#34;*OOOOOOOO*......&#34;,
&#34;*OOOO**OOO*.....&#34;,
&#34;*OOO*..*OOO*....&#34;,
&#34;*OO*....*OOO*...&#34;,
&#34;*O*......*OOO*..&#34;,
&#34;**........*OOO*.&#34;,
&#34;*..........*OOO*&#34;,
&#34;............*OO*&#34;,
&#34;.............***&#34;
};
int x, y;
for (y = 0; y < 16; y++) {
for (x = 0; x < 16; x++) {
if (cursor[y][x] == &#39;*&#39;) { /* *处为黑色 */
mouse[y * 16 + x] = COL8_000000;
}
if (cursor[y][x] == &#39;O&#39;) { /* O处为白色 */
mouse[y * 16 + x] = COL8_FFFFFF;
}
if (cursor[y][x] == &#39;.&#39;) { /* .处为背景色 */
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)
/*作用:将buf中描绘的图形显示在屏幕上
目前用来将init_mouse_cursor8中准备好的鼠标图形显示在屏幕上
参数解释:vram vxsize:显存地址和显存列数; pxsize pysize:想要显示的图像大小(对于鼠标xy大小都是16),
px0 py0:指定图形在画面上的显示位置; buf:待显示的图像的信息数组,想要显示鼠标的话这里传入init_mouse_cursor8中的mouse
bxsize:buf中每一行的像素数,即buf的列宽,一般来说bxsize和pxsize是相等的 */
{
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;
}
五、附录
暂无 |
|