30天自制操作系统之叠加处理

前言
  • 我们通过往显存Vram里面直接设置像素的颜色来设置显示某个对象
  • 对于数字或者字母,我们将其显示放置在一个16*16的数组当中,然后将其遍历,显示在画面的某个位置
static char cursor[16][16] = {
		"**************..",
		"*OOOOOOOOOOO*...",
		"*OOOOOOOOOO*....",
		"*OOOOOOOOO*.....",
		"*OOOOOOOO*......",
		"*OOOOOOO*.......",
		"*OOOOOOO*.......",
		"*OOOOOOOO*......",
		"*OOOO**OOO*.....",
		"*OOO*..*OOO*....",
		"*OO*....*OOO*...",
		"*O*......*OOO*..",
		"**........*OOO*.",
		"*..........*OOO*",
		"............*OO*",
		".............***"
	};
加快更新速度
  • 对于叠加处理,SheetFresh是核心
  • 他将处于显示的层,从高到低依次绘制。这样会导致,鼠标只要稍微移动就会重新绘制,字符进行更新的时候也会重新绘制
for (h = 0; h <= ctl->top; h++) {
		sht = ctl->sheets[h];
		buf = sht->buf;
		for (by = 0; by < sht->bysize; by++) {
			vy = sht->vy0 + by;
			for (bx = 0; bx < sht->bxsize; bx++) {
				vx = sht->vx0 + bx;
				c = buf[by * sht->bxsize + bx];
				if (c != sht->col_inv) {
					vram[vy * ctl->xsize + vx] = c;
				}
			}
		}
	}
  • 一开始只有3层,每一次重新绘制需要刷新 3 * 320 * 640 = 614400个像素,这是一个巨大的浪费。
  • 但是对于鼠标的移动而言,我们只要更新移动前的区域和移动后的区域就可以了
  • 对于字符的每一次更新,也只需要更新指定的区域即可。
  • 因此就可以对SheetFresh进行重写SheetFreshSub
  • 但是SheetFreshSub的实现是基于一个if判断,即对所有的层的坐标进行判断,如果在指定的范围内就继续向下执行,取颜色然后更新Vram
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
{
	int h, bx, by, vx, vy;
	unsigned char *buf, c, *vram = ctl->vram;
	struct SHEET *sht;
	for (h = 0; h <= ctl->top; h++) {
		sht = ctl->sheets[h];
		buf = sht->buf;
		for (by = 0; by < sht->bysize; by++) {
			vy = sht->vy0 + by;
			for (bx = 0; bx < sht->bxsize; bx++) {
				vx = sht->vx0 + bx;
				if (vx0 <= vx && vx < vx1 && vy0 <= vy && vy < vy1) {
					c = buf[by * sht->bxsize + bx];
					if (c != sht->col_inv) {
						vram[vy * ctl->xsize + vx] = c;
					}
				}
			}
		}
	}
	return;
}
  • 这样会平白无故的执行很多次if语句,原来都是对于buf数组,bx=0,by = 0 开始
  • 其实我们只需要根据指定的Vx, Vy 范围然后反推出其bx,by即可,即重新推导出for循环的范围
    • 然后在这种情况下有三种情况
    • 第一是,整个层级恰好落在范围内
    • 第二是,整个层级左半边在范围内或者整个层级右半边在范围内
    • 第三是,整个层级完全在范围之外【这种情况下,要么x全部小于0,要么全部大于xsize,因为无法通过bx<bx1的判断,for循环直接退出】
sht = ctl->sheets[h];
		buf = sht->buf;
		/* vx0~vy1を使って、bx0~by1を逆算する */
		bx0 = vx0 - sht->vx0;
		by0 = vy0 - sht->vy0;
		bx1 = vx1 - sht->vx0;
		by1 = vy1 - sht->vy0;
		if (bx0 < 0) { bx0 = 0; }
		if (by0 < 0) { by0 = 0; }
		if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }
		if (by1 > sht->bysize) { by1 = sht->bysize; }
		for (by = by0; by < by1; by++) {
			vy = sht->vy0 + by;
			for (bx = bx0; bx < bx1; bx++) {
				vx = sht->vx0 + bx;
				c = buf[by * sht->bxsize + bx];
				if (c != sht->col_inv) {
					vram[vy * ctl->xsize + vx] = c;
				}
			}
		}

在这里插入图片描述

在这里插入图片描述

闪烁问题
其一
  • 首先我们设置一个持续累加的数字Count,然后在窗口进行显示,会发现该窗口不停的闪烁
  • 问题在于,SheetFresh刷新的时候是总是从下往上刷新,因此数字会暂时的消失,然后又出现。
  • 解决办法就是——在刷新的时候指定一个高度,对于指定高度以上的进行画面刷新
    • 当图层移动的时候,原先位置的低层级会显示出来,所以从0到top进行刷新,而新位置的高层级受到影响,从height到top进行刷新
    • 当图层只是单纯的SheetFresh的时候,只需要从其当前height到top更新即可
    • 当图层只是单纯的改变层级时,有很多情况,具体分析。
其二
  • 这样依旧会有问题,当鼠标停放在窗口上面的时候,会发现鼠标在不停的闪烁
  • 问题还是存在,我们仅仅需要刷新该图层所占据的像素,而鼠标的层级高于图层,所以其重叠的部分不需要刷新
  • 解决办法就是——新建一个和Vram同样大小的数组Map,然后在写入颜色的地方更改为写入其层级SID,最后在SheetFresh的时候,根据height和Map只刷新该层即可
				vx = sht->vx0 + bx;
				if (buf[by * sht->bxsize + bx] != sht->col_inv) {
					map[vy * ctl->xsize + vx] = sid;
				}
  • 我们需要更新Map,在SheetSlide即层级移动,和SheetUpDown更改层级时。然后在SheetFresh时使用Map
				vx = sht->vx0 + bx;
				if (map[vy * ctl->xsize + vx] == sid) {
					vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx];
				}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值