找回密码
 立即注册
查看: 174|回复: 0

day01——day08:(7)图形处理库:graphic.c

[复制链接]
发表于 2023-1-23 19:39 | 显示全部楼层 |阅读模式
一、已解决疑点(答案在注释中)

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 + '字符' * 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] = {
                "**************..",
                "*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') {  /* 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)
        /*作用:将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;
}

五、附录

暂无
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-28 03:57 , Processed in 0.094219 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表