首页 >> 大全

30天自制操作系统(day11)

2024-01-07 大全 37 作者:考证青年

第11天:制作窗口 1、内容1:添加一个窗口图层有哪些步骤?(格式:文字说明+对应代码)

步骤一:创建描绘窗口的函数。

void window(unsigned char* buf, int xsize, int ysize){static char closebtn[15][17] = {"@@@@@@@@@@@@@@@@@","@$$$$$$$$$$$$$$$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQ@@QQQQ@@QQ$@","@$QQQQ@@QQ@@QQQ$@","@$QQQQQ@@@@QQQQ$@","@$QQQQQQ@@QQQQQ$@","@$QQQQQ@@@@QQQQ$@","@$QQQQ@@QQ@@QQQ$@","@$QQQ@@QQQQ@@QQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$$$$$$$$$$$$$$$@","@@@@@@@@@@@@@@@@@@"};static char smallbtn[15][17] = {"@@@@@@@@@@@@@@@@@","@$$$$$$$$$$$$$$$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQ@@@@@@@@@QQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$QQQQQQQQQQQQQ$@","@$$$$$$$$$$$$$$$@","@@@@@@@@@@@@@@@@@@"};static char bigbtn[15][17] = {"@@@@@@@@@@@@@@@@@","@$$$$$$$$$$$$$$$@","@$QQQQQQQQQQQQQ$@","@$QQ@@@@@@@@@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@QQQQQQQ@QQ$@","@$QQ@@@@@@@@@QQ$@","@$QQQQQQQQQQQQQ$@","@$$$$$$$$$$$$$$$@","@@@@@@@@@@@@@@@@@@"};int x, y;char c;boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0);//横boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1);//横boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1);//竖boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2);//竖boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2);//竖boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1);//竖boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3);//涂boxfill8(buf, xsize, COL8_FFFFFF, 3, 3, xsize - 4, 20);//框boxfill8(buf, xsize, COL8_000000, 3, 21, xsize - 3, 21);//线boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2);//横boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1);//横for (y = 0; y < 15; y++) {for (x = 0; x < 17; x++) {c = closebtn[y][x];if (c == '@') {	c = COL8_000000;}else if (c == '$') {	c = COL8_848484;}else if (c == 'Q') {c = COL8_FFFFFF;}else {c = COL8_FFFFFF;}buf[(5 + y) * xsize + (xsize - 21 + x)] = c;}}for (y = 0; y < 15; y++) {for (x = 0; x < 17; x++) {c = smallbtn[y][x];if (c == '@') {	c = COL8_000000;}else if (c == '$') {	c = COL8_848484;}else if (c == 'Q') {c = COL8_FFFFFF;}else {c = COL8_FFFFFF;}buf[(5 + y) * xsize + (xsize - 21 - 40 + x)] = c;}}for (y = 0; y < 15; y++) {for (x = 0; x < 17; x++) {c = bigbtn[y][x];if (c == '@') {	c = COL8_000000;}else if (c == '$') {	c = COL8_848484;}else if (c == 'Q') {c = COL8_FFFFFF;}else {c = COL8_FFFFFF;}buf[(5 + y) * xsize + (xsize - 21 - 20 + x)] = c;}}return;
}

步骤二:定义图层包(结构体),建立图层(SHEET),建立缓冲区buf(地址)

步骤三:为窗口取得新生成的未被使用的图层,初始化图层

步骤四:为窗口图层分配内存

320*170是窗口的大小

步骤五:设置窗口图层的缓冲区大小和透明色

步骤六:调用描绘窗口函数和显示函数,即内容初始化

步骤七:设置可上下左右移动窗口图层函数,即设置图层显示位置的起始坐标

(mx,my)是窗口的左上角。

步骤八:设置窗口图层高度

步骤九:刷新屏幕显示。

0,0为左上角,后两个参数为右下角

2、内容2:教材202页,为什么鼠标移动到最右边左边会出现鼠标图案,为什么右边只有一个鼠标,左边却有很多?

因为作者在内容一中只是改动了鼠标移动的边界,使鼠标可以在右边隐藏起来。这样虽然实现了,但是之前为了显示鼠标图层,函数会把图层内容写入到VRAM中,因此,即使鼠标图层的一部分处在了画面之外,函数依然会刷新图层,包括画面以外的部分,但在右边已经没法写入到VRAM中,函数会自动将画面外的图层部分写入到左边所对应的VRAM中。所以鼠标移动最右边后,左边会出现鼠标图案,但在画面中的部分在每次移动之后都会刷新,将之前的释放,但在画面外的内容,在每次移动后,不会对之前的内容刷新释放,所以就会出现了右边只有一个鼠标,左边有很多。具体如下:

我们由上一天内容知道,图层移动的时候会调用()和这两个函数:

对鼠标的刷新:

我们知道鼠标的坐标是经过修正的,所以传入的old图层的起始位置是在合理范围内。

查看函数:

对我们有用的是最后的显示部分,因为不管鼠标在哪显示,都用用到像素点

如果按照书上的方法修改,根据像素点公式(一维计算)会导致刷新的像素点往后偏移16位(相当于往右),所以在屏幕左边会出现鼠标。对刷新old图层来说,传入的参数vx0=mx和vx1>xsize,对新图层来说,也是vx0=mx和vx1>xize,而且老图层和新图层的vx1值是相同的,因为当我们把鼠标放到最右边的时候,传入的mx都是同一个值,所以计算出的vx1也是同一个值(mx+16),这个时候两次调用的bx1相同,会先刷新一次老的,再刷新一次新的,那还是在原来的位置,所以鼠标只能在左边的固定范围内出现。刷新的时候因为屏幕的背景是按照一样的计算公式填充的,所以在边界移动的时候会有痕迹保留,也就说old的值还存在背景中,背景图层在刷新的时候会把“遗留”下来的一起刷新,可能是鼠标的颜色,也可能是黑色。

改正方法:在函数里面的循环刷新之前,添加判断

3、内容3:教材216页,每个图层的sid是如何设置的?具体数值等于多少?举例说明,建议编程打印sid进行验证。

Sid变量首次出现在函数中,保存的是每个图层相对于的位置,作者给出的解释是减法计算得出的(地址)图层号码,所以说实际上sid是一个地址,是sheet ID的缩写,出现在函数中是这种形式:

图像形式:相当于一个图层体包含的多个图层每个图层有固定的地址,用当前图层的地址减去最下面图层的地址就可以得出当前的sid号了

可以理解成图层的标号1,2,3………

4、内容4:教材216-217页,结合代码,解释刷新函数()的参数和实现逻辑。

void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1)
参数ctl是图层控制结构体指针,参数vx0、vy0、vx1、vy1是指定刷新图层的范围,参数h0是需要刷新的最低图层的高度,参数h1是需要刷新的最高图层的高度。
实现逻辑:if (vx0 < 0) { vx0 = 0; }if (vy0 < 0) { vy0 = 0; }if (vx1 > ctl->xsize) { vx1 = ctl->xsize; }if (vy1 > ctl->ysize) { vy1 = ctl->ysize; }
首先判断刷新范围有没有超过画面,如果超过了,就对其进行修正。for (h = h0; h <= h1; h++) {//只对h0到h1的图层进行更新操作。sht = ctl->sheets[h];//当前图层的地址buf = sht->buf;//当前图层的缓冲区内容sid = sht - ctl->sheets0;
计算每个图层的sid,在叠加部分进行刷新,利用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; }
根据vx0、vy0、vx1、vy1倒推bx0、by0、bx1、by1,得到刷新范围。for (by = by0; by < by1; by++) {vy = sht->vy0 + by;for (bx = bx0; bx < bx1; bx++) {vx = sht->vx0 + bx;if (map[vy * ctl->xsize + vx] == sid) {
判断是否可以绘制(比如说当前图层号码为2,那么只绘制2那层)vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx];}}}}
最后将缓存写到VRAM中,只有当前sid和map中该像素处sid相等,才将缓存写到VRAM中。

5、内容5:教材217页,结合代码,解释滑动函数()的参数和实现逻辑,注意内部调用和的传参,特别是高度参数,为什么这样传。

void sheet_slide(struct SHEET *sht, int vx0, int vy0)
参数sht是图层指针,vx0、vy0是新图层左上角的坐标。
实现逻辑:
struct SHTCTL *ctl = sht->ctl;
首先得到图层控制结构体指针。int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
old_vx0,old_vy0表示原来的图层sht->vx0 = vx0;sht->vy0 = vy0vx0,vy0表示新的图层
然后得到移动前和移动后的图层的左上角坐标。if (sht->height >= 0) { 
如果正在显示,按照新图层的信息进行刷新sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
绘制原来图层位置的新地图,因为是原来的位置,图层移走了,无法判断图层移动之后的情况,所以旧图层下面和上面的正在显示的图层都需要重新刷新,要从0开始刷新sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height);
绘制新图层位置的新地图,刷新移动后图层的图层范围,从正在显示的图层高度一直刷新到最高层,因为新图层是插入的一层,所以在插入的高度以下的图层都没有发生变化,但是以上的图层都变化了,所以需要刷新移动后图层到最高层之间的图层。																  	sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1);
调用sheet_refreshsub函数,因为移动前的图层已经移走了,所以需要对正在显示的移动前图层以下的图层进行描绘,所以高度是0~sht->height-1sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height);
对于移动后的图层来说,只需要描绘移动的那一个图层即可,所以高度是sheet->height~sheet->height,也就是sheet->height的高度这一个图层。或者可以理解为新的图层地图只是在新图层的高度以上进行了刷新,所以新高度的地图已经绘制好了,直接按照地图刷新当前这一高度的图层就可以了}
这样传的原因是,只绘制了中间变化的图层,而不需要重新绘制鼠标图层,从而消除了鼠标因为自身不停的被覆盖再绘制所产生的闪烁。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了