前言
- 我们通过往显存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];
}