day11 30天自制操作系统

第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图层的起始位置是在合理范围内 。
查看函数:
【day1130天自制操作系统】对我们有用的是最后的显示部分,因为不管鼠标在哪显示,都用用到像素点
如果按照书上的方法修改,根据像素点公式(一维计算)会导致刷新的像素点往后偏移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-1 。sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height);对于移动后的图层来说,只需要描绘移动的那一个图层即可,所以高度是sheet->height~sheet->height , 也就是sheet->height的高度这一个图层 。或者可以理解为新的图层地图只是在新图层的高度以上进行了刷新,所以新高度的地图已经绘制好了 , 直接按照地图刷新当前这一高度的图层就可以了}这样传的原因是,只绘制了中间变化的图层 , 而不需要重新绘制鼠标图层,从而消除了鼠标因为自身不停的被覆盖再绘制所产生的闪烁 。