1.【VGA图形系统初探】

2021-01-03  本文已影响0人  月下蓑衣江湖夜雨

提示:可以将virtualbox虚拟机界面大小设置大一些。https://jingyan.baidu.com/article/6525d4b13b7d0fac7d2e94ef.html

1、设置背景色为白色

设置背景色为白色
前提条件:需要要将VGA显卡设置为图形模式,在boot中写,代码如下:
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;设置VGA图形格式
  mov al, 0x13
  mov ah, 0x00
  int 0x10
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;

AH=0x00;
AL=模式:(省略了一些不重要的画面模式)
0x03:16位字符模式,80x25
0x12:VGA图形模式,640x480x4位彩色模式,独特的4面存储模式
0x13:VGA图形模式,320x200x8位彩色模式,调色板模式
0x6a:扩展VGA图形模式,800x600x4位彩色模式,独特的4面存储模式(有的显卡不支持这种模式)
返回值:无
我们暂且选择0x13模式,因为8位彩色模式可以使用256种颜色,这一点看来不错。
写显卡

; 导出函数
global  write_mem8

[SECTION .text]
; ========================================================================
;                  void write_mem8(int addr, int data);
; ========================================================================
write_mem8:
    mov ecx, [esp + 4]      ; [esp + 4]中存放的是地址,将其读入ecx
    mov al, [esp + 8]       ; [esp + 8]中存放的是数据,将其读入al
    mov [ecx], al
    ret

c语言设置背景色位白色

void set_background_white(){    
    for(int i = 0xa0000; i<=0xaffff; i++){
        write_mem8(i, 15);
    }
}

2、设置背景为条纹图案

条纹背景
void set_background_stripe(){   
    for(int i = 0xa0000; i<=0xaffff; i++){
        write_mem8(i, i & 0x0f);
    }
}

c语言可以直接使用指针操作内存,不用借助于汇编!
char *p; // 用于BYTE类地址
short *p // 用于WORD类地址
int *p // 用于DWORD类地址

void set_background_stripe(){   
    char *p;
    for(int i = 0xa0000; i<=0xaffff; i++){
        p = (char *) i;
        *p = i & 0x0f;
    }
}

3、设置调色板,色号
这次使用的是320x200的8位颜色模式,色号使用8位(二进制)数,也就是只能使用0~255的数。
RGB使用6位16进制数,也就是24位(二进制)来指定颜色。
这个8位彩色模式,是由程序随意指定0~255的数字所对应的颜色的。
例如25号颜色对应#ffffff,26号颜色对应对应#123456,等,这种方式叫叫做调色板。(palette)
如果程序员不做任何设定,0号颜色就是#000000,15号颜色就是#ffffff。
c:初始化调色板

// 初始化调色板
void init_palette(){
    // 我们只设置如下16种颜色就可以了
    static unsigned char table_rgb[16*3] = {
        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);
}

// 设置调色板
void set_palette(int start, int end, unsigned char *rgb){
    int eflags = io_load_eflags();    // 记录中断许可标志的值
    io_cli();                         // 将中断许可标志置为0,禁止中断
    
    io_out8(0x03c8, start);
    for(int 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;
    }
    
    io_store_eflags(eflags);
}

asm:依赖函数

; ========================================================================
;                  void io_out8(int port, int data);
; ========================================================================
io_out8:
    mov edx, [esp + 4]      ; port
    mov al,  [esp + 8]      ; data
    mov dx, al
    ret
    
; ========================================================================
;                  int io_load_eflags();
; ========================================================================
io_load_eflags:
    pushfd         ; 指push eflags
    pop eax        ; 函数执行完毕后,如果返回值小于等于4字节,则会将值保存在寄存器eax中
    ret

; ========================================================================
;                  void io_store_eflags(int eflags);
; ========================================================================
io_load_eflags:
    mov eax, [esp + 4]
    push eax
    popfd          ; 指pop eflags
    ret     
    
; ========================================================================
;                  void io_cli();
; ========================================================================
io_cli:
    cli
    ret 

c语言函数返回值问题https://blog.csdn.net/wanna_wsl/article/details/70550825

4、绘制矩形

画面上由320x200=64000个像素。
假设左上点的坐标是(0, 0),右下点的坐标是(319, 199),那么像素坐标(x,y)对应的VRAM地址为:
0xa0000 + x + y*320

效果
绘制函数
// 绘制矩形
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1){
    for(int y = y0; y <= y1; y++){
        for(int x = x0; x <= x1; x++){
            vram[y * xsize + x] = c;
        }
    }
}

调用

    // 绘制矩形
    char *p = (char *) 0xa0000;
    boxfill8(p, 320, COL8_FF0000,  20, 20, 120, 120);
    boxfill8(p, 320, COL8_00FF00,  70, 50, 170, 150);
    boxfill8(p, 320, COL8_0000FF, 120, 80, 220, 180);

5、绘制界面

效果
// 绘制ui
void draw_ui(){
    init_palette();
    
    char *vram = (char *) 0xa0000;
    const int xsize = 320;
    const int ysize = 200;
    
    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);
}
上一篇下一篇

猜你喜欢

热点阅读