动手写操作系统11----图层技术实现

        本节实现图层技术,之前实现对于内存信息的图形化展示,但是由于没有使用内存管理功能,鼠标绘制和字符显示都是直接往显存位置处写数据,这样就会导致当移动鼠标重绘时直接改变显存位置数据而将字符数据直接擦除掉。这里采用图层技术,即背景窗口,字符以及鼠标数据不直接写入显存位置处,而是首先写入到不同的内存中,不同的图层对应不同的内存,当执行刷新函数时,由下到上开始绘制每一层图层,这样便可以实现不同图层的分别显示处理而不影响。

                                                                     

图层技术实现

定义一个图层管理器,其中含有许多图层元素,每个图层都对应一块内存,图层数据首先缓存在对应内存中,当执行刷新操作时,再将不同图层的数据依次写入显存中实现显示功能。

图层管理器定义  最多支持256个图层 top标识当前最大图层  即窗口最上方图层

#define MAX_SHEETS 256
typedef struct _SHTCTL{
	unsigned char * vram; //vram对应显存地址
	int xsize, ysize, top; //xsize, ysize 代表整个显示界面的宽和高,top 表示当前要显示几个图层
	SHEET *sheets[MAX_SHEETS]; //sheets0 是用来存储图层对象的数组
	SHEET sheets0[MAX_SHEETS]; //sheets指向下面图层数组中的对应图层对象
}SHTCTL;

每个图层的定义

weight用来表示图层的权重,即权重越大,越位于窗口上方  其值为-1则表示该图层不显示

/*
图层数据结构
buf用来记录图层上所描画内容的地址。
图层的整体大小:width、height。
图层在画面上位置的坐标:x、y。
col_inv为透明色色号。
weight 为图层显示层级权重 -1表示隐藏
flags用于存放有关图层的各种设定信息。(使用状况)
*/
typedef struct _SHEET{
	unsigned char *buf;
	int width, height, x, y, col_inv, weight, flags;
}SHEET;

对于图层操作函数操作定义

SHTCTL *shtctl_init(MEMMAN *memman, unsigned char *vram, int xsize, int ysize);

SHEET *sheet_alloc(SHTCTL *ctl);

void sheet_free(SHTCTL *ctl, SHEET *sht);

void sheet_setRect(int x, int y, int width, int height, int col_inv, SHEET *sht, unsigned char *buf);

void sheet_setWeight(SHTCTL *ctl, SHEET *sht, int weight);

int sheet_refresh(SHTCTL *ctl);

void sheet_slide(SHTCTL *ctl, SHEET *sht, int vx0, int vy0);

图层管理器初始化实现

分配内存 设置图层对应显存地址 图层大小以及每个图层初始化可用状态

//未使用
#define SHEET_FREE 0
//已使用
#define SHEET_USE 1

//初始化图形管理器
SHTCTL *shtctl_init(MEMMAN *memman, unsigned char *vram, int xsize, int ysize){
	SHTCTL *ctl = (SHTCTL *)memman_alloc(memman, SIZE_OF_SHTCTL);
	if(ctl==0){
		return 0;
	}
	ctl->vram = vram;
	ctl->xsize = xsize;
	ctl->ysize = ysize;
	ctl->top = -1;
	for(int i=0; i<MAX_SHEETS; i++){
		ctl->sheets0[i].flags = SHEET_FREE;
	}
	return ctl;
}

从图层管理器分配一个可用图层 找个第一个可用图层并返回

//分配一个图层
SHEET *sheet_alloc(SHTCTL *ctl){
	SHEET *sht;
	for(int i=0; i<MAX_SHEETS; i++){
		if(ctl->sheets0[i].flags == 0){
			sht = &ctl->sheets0[i];
			ctl->sheets[i] = sht;
			sht->flags = SHEET_USE;
			sht->weight = -1;
			return sht;
		}
	}
	return 0;
}

释放一个图层  调整其权重为-1  标识为可用状态

//释放一个图层
void sheet_free(SHTCTL *ctl, SHEET *sht){
	sheet_setWeight(ctl, sht, -1);
	sht->weight = -1;
	sht->flags = SHEET_FREE;
}

设置图层基本数据

//初始化图层数据
void sheet_setRect(int x, int y, int width, int height, int col_inv, SHEET *sht, unsigned char *buf){
	sht->x = x;
	sht->y = y;
	sht->width = width;
	sht->height = height;
	sht->buf = buf;
	sht->col_inv = col_inv;
}

刷新图层管理器操作  遍历每一个图层由下到上往显存相应位置写数据,这里有一个透明色的概念,即对应当前图层以及其下一层图层,如果当前图层要显示的色彩与其下一层色彩相同,则不需要刷新。

//刷新整个图层管理器
int sheet_refresh(SHTCTL *ctl){
	unsigned char *vram = ctl->vram;
	//由底向上刷新图层
	for(int h=0; h<=ctl->top; h++){
		SHEET *sht = ctl->sheets[h];
		unsigned char *buf = sht->buf;
		for(int by=0; by<sht->height; by++){
			int vy = sht->y + by;
			for(int bx=0; bx<sht->width; bx++){
				int vx = sht->x + bx;
				unsigned char c = buf[by*sht->width+bx];
				if(c != sht->col_inv){
					vram[vy*ctl->xsize+vx] = c;
				}
			}
		}
	}
	return 0;
}

最核心的调整图层权重函数实现

//设置某个图层的权重
//图形权重越大 在图层管理器数组中索引越大 显示在屏幕上方
//权重-1表示图层不显示
void sheet_setWeight(SHTCTL *ctl, SHEET *sht, int weight){
	//保存旧权重
	int old = sht->weight;
	if(weight > ctl->top+1){
		weight = ctl->top+1;
	}
	if(weight < -1){
		weight = -1;
	}
	//设置新权重
	sht->weight = weight;
	int h;
	// 新权重往下调整
	if(old > weight){
		//该图层还需要显示
		if(weight >= 0){
			//0---weight--old---top
			//将old位置图层放置到weight位置
			//将[weight-1,old]依次后移
			//将old放入到weight位置
			for(h=old; h>weight; h--){
				ctl->sheets[h] = ctl->sheets[h-1];
				ctl->sheets[h]->weight = h;
			}
			ctl->sheets[weight] = sht;
		}else{
			//该old图层不需要显示
			0---weight--old---top
			//将[old+1,top]依次后移
			if(ctl->top > old){
				for(h=old; h<ctl->top; h++){
					ctl->sheets[h] = ctl->sheets[h+1];
					ctl->sheets[h]->weight = h;
				}
			}
			ctl->top--;
		}
	}else if(old < weight){ //新权重往上调整
	    //0---old--weight---top
		//old图层本来是显示状态
		//将[old+1,weight]后移
		//将old放入到weight位置
		if(old>=0){
			for(h=old; h<weight; h++){
				ctl->sheets[h] = ctl->sheets[h+1];
				ctl->sheets[h]->weight = h;
			}
			ctl->sheets[weight] = sht;
		}else{ //old图层是未显示状态
		    //新增一个图层
			//0-----weight---top
			//[weight, top]后移
			//将sht放入到weight位置
			if(ctl->top>=0){
				for(h=ctl->top; h>=weight; h--){
					ctl->sheets[h+1] = ctl->sheets[h];
					ctl->sheets[h+1]->weight = h+1;
				}
			}
			ctl->sheets[weight] = sht;
			ctl->top++;
		}
	}
	sheet_refresh(ctl);
}

最基本分为两种情况  权重变大与权重变小

1.对于权重变小   并且新权重等于-1 则说明该图层出于不显示状态

0----old----top   

0---(old+1)----top

即相当于从一个数组中去掉某一个元素old  将[old+1,top]依次前移即可

2.权重变小  新权重大于-1 还需要显示

0----w----old----top

0----old w----(old-1)----top

即将[w,old-1]依次后移  将old插入到w位置处

3.权重变大   之前权重大于-1  即本来窗口就是处于显示状态

0-----old----w----top

0----old-1----w----old----top

即将[old+1,w]依次前移,将old至于w位置处

4.权重变大   之前权重等于-1  即本来窗口处于非显示状态  则需要增加一个新图层

0------top

0----w----top

将[w,top]依次后移 将新窗口置于w位置处

移动图层实现

//移动窗口
void sheet_slide(SHTCTL *ctl, SHEET *sht, int vx0, int vy0){
	sht->x = vx0;
	sht->y = vy0;
	if(sht->weight >= 0){
		sheet_refresh(ctl);
	}
}

主函数实现如下:

#include<stdio.h>
#include "os.h"
#include "ascii_font.h"
//#include "mem_util.h"
//#include "win_sheet.h"

static char keybuf[32];
static char mousebuf[128];

static FIFO8 keybufInfo;
static FIFO8 mousebufInfo;

//鼠标移动模型
static MouseDes mouseDes;

static char keyval[4] = {'0','x'};

//内存管理器
static MEMMAN* memman;

//图层管理器
static SHTCTL* shtctl;

//背景窗口
static SHEET* shtback;
static unsigned char* shtbackBuf;

//鼠标窗口
static SHEET* shtMouse;
static unsigned char* shtCursorBuf;

//字符显示窗口
static SHEET* shtChar;
static unsigned char* shtCharBuf;

//内存块总数量和地址描述符首地址
static int memCount;
static AddrRangeDesc* memDesc;

//kernel程序入口
void kernel_main(){
	
	//初始化调色板
    initPallet();
	
	// 初始化键盘&鼠标缓冲区
	fifo8_init(&keybufInfo, 32, keybuf);
	fifo8_init(&mousebufInfo, 128, mousebuf);
	
	//初始化鼠标电路
	init_mouse();
	
	//初始化内存管理器
	init_memman(memman);
	
	//初始化图层管理器
	shtctl = shtctl_init(memman, (unsigned char *)VGA_ADDR, SCREEN_WIDTH, SCREEN_HEIGHT);
	
	//背景图层
	shtback = sheet_alloc(shtctl);
	shtbackBuf = (unsigned char *)memman_alloc(memman, SCREEN_WIDTH*SCREEN_HEIGHT);
	draw_desktop();
	sheet_setRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, -1, shtback, shtbackBuf);
	sheet_setWeight(shtctl, shtback, 0);
	
	//鼠标图层
	shtMouse = sheet_alloc(shtctl);
	shtCursorBuf = (unsigned char *)memman_alloc(memman, 16*16);
	mouseDes.x = (SCREEN_WIDTH-16)/2;
	mouseDes.y = (SCREEN_HEIGHT-28-16)/2;
	mouseDes.phase = 0;
	init_mouse_cursor(shtCursorBuf, COL8_008484, 16);
	sheet_setRect(mouseDes.x, mouseDes.y, 16, 16, COL8_008484, shtMouse, shtCursorBuf);
	sheet_setWeight(shtctl, shtMouse, 2);
	
	//字符窗口
	shtChar = sheet_alloc(shtctl);
	shtCharBuf = (unsigned char *)memman_alloc(memman, SCREEN_WIDTH*SCREEN_HEIGHT);
	memman_set(shtCharBuf, COL8_008484, SCREEN_WIDTH*SCREEN_HEIGHT);
	sheet_setRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, COL8_008484, shtChar, shtCharBuf);
	sheet_setWeight(shtctl, shtChar, 1);
	
	
	//计算显示的内存块索引
	static int count = 0;
	
    for(;;){
		if (keybufInfo.len > 0) {
			io_cli();
			char data = fifo8_get(&keybufInfo);
			//回车键
			if(data == 0x1C){
				showMemInfo(memDesc + count, count, shtCharBuf);
				count += 1;
				if(count > memCount){
					count = 0;
				}
			}
			io_seti();
		} else if (mousebufInfo.len > 0) {
			io_cli();
			for(int t=0;t<mousebufInfo.len;t++){
				mouseCursorMoved(&mouseDes, COL8_008484);
			}
			io_seti();
		} else {
			io_hlt();
		}
    }
}

void initPallet(){

	// 注意此指针变量的声明
    unsigned char *p = table_rgb;
	//读取eflags寄存器值
    int flag = io_readFlag();
	//关中断
    io_cli();
	//写入调色板编号
    io_out8(0x03c8, 0);
	//调色板颜色与坐标索引对应值
    for(int i=0; i<16; i++){
        io_out8(0x03c9, p[0]/4);
        io_out8(0x03c9, p[1]/4);
        io_out8(0x03c9, p[2]/4);
        p += 3;
    }	
    //将eflags寄存器重新赋值
    io_writeFlag(flag);
	// 开中断
	// 此处注意开中断
	// 在写调色板信息时关闭中断 这里要及时打开中断 否则后面中断无法响应
	io_seti();
}

//向内存指定位置写入一块矩形数据
void fillRect(int x, int y, int width, int height, char colIndex, unsigned char *buf){
    for(int i=y; i<=y+height; i++){
        for(int j=x; j<=x+width; j++){
            buf[i*SCREEN_WIDTH+j] = colIndex;
        }
    }
}

void draw_desktop(){

    fillRect(0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-29, COL8_008484, shtbackBuf);
    fillRect(0, SCREEN_HEIGHT-28, SCREEN_WIDTH-1, 28, COL8_848484, shtbackBuf);

	fillRect(0, SCREEN_HEIGHT-27, SCREEN_WIDTH, 1, COL8_848484, shtbackBuf);
	fillRect(0, SCREEN_HEIGHT-26, SCREEN_WIDTH, 25, COL8_C6C6C6, shtbackBuf);
	
	fillRect(3, SCREEN_HEIGHT-24, 56, 1, COL8_FFFFFF, shtbackBuf);
	fillRect(2, SCREEN_HEIGHT-24, 1, 20, COL8_FFFFFF, shtbackBuf);

	fillRect(3, SCREEN_HEIGHT-4, 56, 1, COL8_848484, shtbackBuf);
	fillRect(59, SCREEN_HEIGHT-23, 1, 19, COL8_848484, shtbackBuf);

	fillRect(2, SCREEN_HEIGHT-3, 57, 0, COL8_000000, shtbackBuf);
	fillRect(60, SCREEN_HEIGHT-24, 0, 19, COL8_000000, shtbackBuf);

	fillRect(SCREEN_WIDTH-47, SCREEN_HEIGHT-24, 43, 1, COL8_848484, shtbackBuf);
	fillRect(SCREEN_WIDTH-47, SCREEN_HEIGHT-23, 0, 19, COL8_848484, shtbackBuf);

	fillRect(SCREEN_WIDTH-47, SCREEN_HEIGHT-3, 43, 0, COL8_FFFFFF, shtbackBuf);
	fillRect(SCREEN_WIDTH-3, SCREEN_HEIGHT-24, 0, 21, COL8_FFFFFF, shtbackBuf);
}

void showChar(char *addr, int x, int y, char col, unsigned char *pch, int screenWidth){
    for(int i=0; i<16; i++){
        char ch = pch[i];
        // 对于每一个字符 8*16
        // 从上到下 从右向左依次绘制
        // 遍历每一位 如果1 则将显存对应位置设置为特定颜色
        int off = (y + i) * screenWidth;
        if((ch & 0x01) != 0){
            addr[off+x+7] = col;
        }
        if((ch & 0x02) != 0){
            addr[off+x+6] = col;
        }
        if((ch & 0x04) != 0){
            addr[off+x+5] = col;
        }
        if((ch & 0x08) != 0){
            addr[off+x+4] = col;
        }
        if((ch & 0x10) != 0){
            addr[off+x+3] = col;
        }
        if((ch & 0x20) != 0){
            addr[off+x+2] = col;
        }
        if((ch & 0x40) != 0){
            addr[off+x+1] = col;
        }
        if((ch & 0x80) != 0){
            addr[off+x+0] = col;
        }
    }
}

void draw_char(){
    unsigned char *ascii = ascii_array;
    int x, y = 0;
    for(int i=0x20; i<=0x7f; i++){
        //字符水平间隔为4 竖直间隔为8
        x = (i - 0x20) % 32 * 10;
        y = (i - 0x20) / 32 * 20;
        showChar((char *)VGA_ADDR, x, y, COL8_FFFFFF, ascii+(i-0x20)*16, SCREEN_WIDTH);
    }
}

void init_mouse_cursor(char *vram, char bc, int winW){
	//16*16 Mouse
    //鼠标指针点阵
	static char cursor[16][16] = {
	 "*...............",
	 "**..............",
	 "*O*.............",
	 "*OO*............",
	 "*OOO*...........",
	 "*OOOO*..........",
	 "*OOOOO*.........",
	 "*OOOOOO*........",
	 "*OOOOOOO*.......",
	 "*OOOO*****......",
	 "*OO*O*..........",
	 "*O*.*O*.........",
	 "**..*O*.........",
	 "*....*O*........",
	 ".....*O*........",
	 "......*........."
	};

	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			int off = i*winW+j;
			if (cursor[i][j] == '*') {
				vram[off] = COL8_000000;
			}
			if (cursor[i][j] == 'O') {
				vram[off] = COL8_FFFFFF;
			}
			if (cursor[i][j] == '.') {
				vram[off] = bc;
			}
		}
	}
}

void showString(char *str, int x, int y, char col, unsigned int *buf){
	unsigned char *ascii = ascii_array;
	for(; *str!=0x00; str++){
		showChar((char *)buf, x, y, col, ascii+((char)*str-0x20)*16, SCREEN_WIDTH);
		x += 8;
	}
}

void int_keyboard(char *index){
	//0x20是8259A控制端口
	//0x21对应的是键盘的中断向量。当键盘中断被CPU执行后,下次键盘再向CPU发送信号时,
	//CPU就不会接收,要想让CPU再次接收信号,必须向主PIC的端口再次发送键盘中断的中断向量号
	io_out8(0x20, 0x21);
	unsigned char data = io_in8(PORT_KEYDATA);
	fifo8_put(&keybufInfo, data);
}

char char2HexVal(char c) {
	if (c >= 10) {
		return 'A' + c - 10;
	}
	return '0' + c;
}

void char2HexStr(unsigned char c, char *keyval){
	char mod = c % 16;
	keyval[3] = char2HexVal(mod);
	c = c / 10;
	keyval[2] = char2HexVal(c);
}

//鼠标电路对应的一个端口是 0x64, 通过读取这个端口的数据来检测鼠标电路的状态,
//内核会从这个端口读入一个字节的数据,如果该字节的第二个比特位为0,那表明鼠标电路可以
//接受来自内核的命令,因此,在给鼠标电路发送数据前,内核需要反复从0x64端口读取数据,
//并检测读到数据的第二个比特位,直到该比特位为0时,才发送控制信息
void waitKBCReady(){
	for(;;){
		if((io_in8(PORT_KEYSTA)&0x02)==0){
			break;
		}
	}
}

//初始化键盘控制电路,鼠标控制电路是连接在键盘控制电路上,通过键盘电路实现初始化
void init_mouse(){
	
	waitKBCReady();
	
	//0x60让键盘电路进入数据接受状态
	io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
	waitKBCReady();
	
	//数据0x47要求键盘电路启动鼠标模式,这样鼠标硬件所产生的数据信息,通过键盘电路端口0x60就可读到
	io_out8(PORT_KEYDATA, KBC_MODE);
	waitKBCReady();
	
	io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
	waitKBCReady();
	
	//0xf4数据激活鼠标电路,激活后将会给CPU发送中断信号
	io_out8(PORT_KEYDATA, MOUSECMD_ENABLE);
}

void int_mouse(char *index){
	//当中断处理后,要想再次接收中断信号,就必须向中断控制器发送一个字节的数据
	io_out8(0x20, 0x20);
	io_out8(0xa0, 0x20);
	//读取鼠标数据
	unsigned char data = io_in8(PORT_MOUSEDATA);
	fifo8_put(&mousebufInfo, data);
}

void fifo8_init(FIFO8 *fifo, int size, char *buf){
	fifo->buf = buf;
	fifo->r = 0;
	fifo->w = 0;
	fifo->size = size;
	fifo->len = 0;
	fifo->flag = 0;
}

int fifo8_put(FIFO8 *fifo, char data){
	if(fifo->len == fifo->size){
		return -1;
	}
	fifo->buf[fifo->w] = data;
	fifo->w++;
	if(fifo->w == fifo->size){
		fifo->w = 0;
	}
	fifo->len++;
	return 0;
}

int fifo8_get(FIFO8 *fifo){
	if(fifo->len == 0){
		return -1;
	}
	int data = fifo->buf[fifo->r];
	fifo->r++;
	if(fifo->r == fifo->size){
		fifo->r = 0;
	}
	fifo->len--;
	return data;
}

void handleKeyInterrupt(FIFO8 *keybufInfo){
	io_cli();
	static char keyval[4] = {'0','x'};
	for(int i=0; i<keybufInfo->len; i++){
		char data = fifo8_get(&keybufInfo);
		static int x = 0;
		char2HexStr(data, keyval);
		//showString(keyval, x%SCREEN_WIDTH, x/SCREEN_WIDTH*20, COL8_FFFFFF);
		x += 32;
	}
	io_seti();
}

void handleMouseInterrupt(FIFO8 *mousebufInfo){
	io_cli();
	static char keyval[4] = {'0','x'};
	for(int i=0; i<mousebufInfo->len; i++){
		char data = fifo8_get(&mousebufInfo);
		static int x = 640;
		char2HexStr(data, keyval);
		//showString(keyval, x%SCREEN_WIDTH, x/SCREEN_WIDTH*20, COL8_FFFFFF);
		x += 32;
	}
	io_seti();
}

int mouse_decode(MouseDes *mdec, unsigned char dat){
	int flag = -1;
	if(mdec->phase == 0){
		if(dat == 0xfa){
			mdec->phase = 1;
		}
		flag = 0;
	}
	else if(mdec->phase == 1){
		if((dat&0xc8) == 0x08){
			mdec->buf[0] = dat;
			mdec->phase = 2;
		}
		flag = 0;
	}
	else if(mdec->phase == 2){
		mdec->buf[1] = dat;
		mdec->phase = 3;
		flag = 0;
	}
	else if(mdec->phase == 3){
		mdec->buf[2] = dat;
		mdec->phase  =1;
		mdec->btn = mdec->buf[0]&0x07;
		mdec->offX = mdec->buf[1];
		mdec->offY = mdec->buf[2];
		if((mdec->buf[0]&0x10) != 0){
			mdec->offX |= 0xffffff00;
		}
		if((mdec->buf[0]&0x20) != 0){
			mdec->offY |= 0xffffff00;
		}
		mdec->offY = -mdec->offY;
		flag = 1;
	}
	return flag;
}

void mouseCursorMoved(MouseDes *mdec, char bc){
	unsigned char data = fifo8_get(&mousebufInfo);
	if(mouse_decode(mdec, data) != 0){
		//擦除之前鼠标位置
		//fillRect(mdec->x, mdec->y, 16, 16, bc);
		//计算鼠标新的坐标
		mdec->x += mdec->offX;
		mdec->y += mdec->offY;
		if(mdec->x < 0){
			mdec->x = 0;
		}
		if(mdec->x > SCREEN_WIDTH-16/2){
			mdec->x = SCREEN_WIDTH-16/2;
		}
		if(mdec->y < 0){
			mdec->y = 0;
		}
		if(mdec->y > SCREEN_HEIGHT-16){
			mdec->y = SCREEN_HEIGHT-16;
		}
		//绘制鼠标
		//init_mouse_cursor((char *)VGA_ADDR, mdec->x, mdec->y, COL8_008484);
		sheet_slide(shtctl, shtMouse, mdec->x, mdec->y);
	}
}

// 32位整形数值转换为16进制
char*  intToHexStr(unsigned int d) {
    static char str[11];
    str[0] = '0';
    str[1] = 'X';
    str[10] = 0;
    int i = 2;
    for(; i < 10; i++) {
        str[i] = '0';
    }
    int p = 9;
    while (p > 1 && d > 0) {
        int e = d % 16;
        d /= 16;
        if (e >= 10) {
           str[p] = 'A' + e - 10;
        } else {
            str[p] = '0' + e;
        }
        p--;		
    } 
    return str;
}

void showMemInfo(AddrRangeDesc *desc, int page, unsigned int* buf){
	
	int x = 0, y = 20, t = 8*12;

    fillRect(x, y, SCREEN_WIDTH, SCREEN_HEIGHT-30, COL8_008484, buf);

	showString("page is: ", x, y, COL8_000000, buf);
    char* pPageCnt = intToHexStr(page);
    showString(pPageCnt, x+t, y, COL8_000000, buf);
	
    y += 16;
	showString("BaseAddrL: ", x, y, COL8_000000, buf);
    char* pBaseAddrL = intToHexStr(desc->addrLow);
	showString(pBaseAddrL, x+t, y, COL8_000000, buf);
	
    y += 16;
	showString("BaseAddrH: ", x, y, COL8_000000, buf);
    char* pBaseAddrH = intToHexStr(desc->addrHigh);
	showString(pBaseAddrH, x+t, y, COL8_000000, buf);
  
    y += 16;
	showString("lengthLow: ", x, y, COL8_000000, buf);
    char* pLengthLow = intToHexStr(desc->lenLow);
	showString(pLengthLow, x+t, y, COL8_000000, buf);

    y+= 16;
	showString("lengthHigh: ", x, y, COL8_000000, buf);
    char* pLengthHigh = intToHexStr(desc->lenHigh);
	showString(pLengthHigh, x+t, y, COL8_000000, buf);

    y+= 16;
	showString("type: ", x, y, COL8_000000, buf);
    char* pType = intToHexStr(desc->type);
	showString(pType, x+t, y, COL8_000000, buf);
}

void init_memman(MEMMAN *memman){
	//获取总可用内存块数量
	memCount = mem_block_count();
	
	//内存描述符信息首地址
	memDesc = (AddrRangeDesc*)get_addr_mem_buffer();
	
	int c = 0;
	unsigned int addr;
	unsigned int size;
	unsigned int type;
	//初始化内存管理器
	for(int i=0; i<memCount; i++){
		addr = (memDesc+i)->addrLow;
		size = (memDesc+i)->lenLow;
		type = (memDesc+i)->type;
		//检测所有可用内存
		//以1G内存为例 一共有8块 1,4块是可用内存
		//0x00000000-0x0009FC000
		//0x00010000-0x3FEF0000
		if(type == 1){
			//找到第一块可用内存
			// 从网上资料  直接从第三块内存开始初始化使用会报错
			// 从第一块内存初始化内存管理器,第一块内存加入到内存管理器memman
			// 但是第一块内存要空余4096*1024=0x8000内存用来存放最多4096个内存块
			if(c == 0){
				memman = (MEMMAN *)(addr);
				memman_init(memman);
				memman_free(memman, (unsigned int *)addr+0x8000, size-0x8000);
				c++;
			}else{
				//其余的可用内存块直接放入内存管理器
				memman_free(memman, (unsigned int *)addr, size);
			}
		}
	}
}

修改对应脚本

#!/bin/bash
gcc -m32 -fno-asynchronous-unwind-tables -fno-pic -s -c -o mem_util.o mem_util.c
echo "gcc -m32 -fno-asynchronous-unwind-tables -s -c -o mem_util.o mem_util.c"
gcc -m32 -fno-asynchronous-unwind-tables -fno-pic -s -c -o win_sheet.o win_sheet.c
echo "gcc -m32 -fno-asynchronous-unwind-tables -fno-pic -s -c -o win_sheet.o win_sheet.c"
gcc -m32 -c -fno-asynchronous-unwind-tables -fno-pic os.c -o os.o
echo "gcc -m32 -c -fno-asynchronous-unwind-tables -fno-pic os.c -o os.o"
ld -m elf_i386 -r os.o mem_util.o win_sheet.o -o ckernel.o
echo "ld -m elf_i386 -r os.o mem_util.o win_sheet.o -o ckernel.o"
./objconv -fnasm ckernel.o -o os.asm
echo "./objconv -fnasm os.o -o os.asm"
gcc processAsm.c -o processAsm
echo "gcc processAsm.c -o processAsm"
./processAsm os.asm os_tmp.asm
echo "./processAsm os.asm os_tmp.asm"
rm -rf os.asm
echo "rm -rf os.asm"
mv os_tmp.asm os.asm
echo "mv os_tmp.asm os.asm"
nasm boot.asm
echo "nasm boot.asm"
nasm kernel.asm
echo "nasm kernel.asm"
gcc floppy.c makeFloppy.c -o makeFloppy
echo "gcc floppy.c makeFloppy.c -o makeFloppy"
./makeFloppy boot kernel system.img
echo "./makeFloppy boot kernel system.img"
rm -rf boot kernel makeFloppy processAsm os.asm os.o mem_util.o ckernel.o win_sheet.o
echo "rm -rf boot kernel makeFloppy processAsm os.asm os.o mem_util.o ckernel.o win_sheet.o"
echo "make floppy success"

相应效果如下所示

可知背景图层  字符图层  与鼠标图层是分离的,是互不影响的。

上述实现有一个问题,就是移动鼠标时,刷新图层管理器时过于卡顿,主要是当前刷新逻辑是刷新整个图层,其实当移动鼠标时,只需要刷新移动部分即可,其余部分没有改变是不需要刷新的。

图层技术实现优化

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值