这一章主要是处理之前遇到的图层叠加的问题。【操作系统】30天自制操作系统--(7)鼠标移动与32位切换

一 内存管理优化

上一章的内存管理虽然写好,但是还是有不完善的地方。因为如果不对申请内存的大小有限制的话,时间长了,内存就会呈现碎片化的情况,而且内存管理列表也很有可能达到上限。所以这边单独写一个每次申请4K大小的函数,这样如果调用这个函数,内存就会以一块4K来排列,比较规整(事实上,实际的使用中,会有专门申请大内存的函数和申请小内存的函数,以应对不同的使用场景,内存池的管理也是操作系统的一个重点)。

unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size){unsigned int a;size = (size + 0xfff) & 0xfffff000;a = memman_alloc(man, size);return a;
}int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size){int i;size = (size + 0xfff) & 0xfffff000;i = memman_free(man, addr, size);return i;
}

二 图层叠加处理

之前第7章中遇到了图层覆盖的问题,即移动鼠标的时候,新刷新的区域不会重绘。所以这边引入了图层概念。其中心思想是,创建从大到小的很多张图层,比如说最上面的图层是鼠标,下面的几张是窗口,最下的是壁纸,同时,我们还要通过移动图层的方法来实现鼠标以及窗口的移动 。每次刷新的时候,按照图层的排列,由低到高依次刷新重绘图层,这样就可以实现不同图层之间的叠加处理。

我们使用结构体来表示图层信息和管理图层信息的结构:

/* sheet.c */
#define MAX_SHEETS          256/* SHEET表
(1)buf 记录图层上所描画内容的地址
(2)bxsize * bysize 图层的整体大小
(3)vx0 vy0 示图层在画面上位置的坐标
(4)col_inv 透明色色号
(5)height 表示图层高度
(6)flags 于存放有关图层的各种设定信息 */
struct SHEET {unsigned char *buf;int bxsize, bysize, vx0, vy0, col_inv, height, flags;
};/* SHTCTL表
(1)变量vram、xsize、ysize代表VRAM的地址和画面的大小,但如果每次都 从BOOTINFO查询的话就太麻烦了,所以在这里预先对它们进行赋值操作
(2)top代表最上面图层的高度
(3)sheets0这个结构体用于存放我们准备的256个图层的信息,是无序的
(4)sheets是记忆地址变量的领域,是sheet0按照高度顺序排序的 */
struct SHTCTL {unsigned char *vram;int xsize, ysize, top;struct SHEET *sheets[MAX_SHEETS];struct SHEET sheets0[MAX_SHEETS];
};

封装以下函数进行操作使用:

【1】图层初始化shtctl_init :

struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize){struct SHTCTL *ctl;int i;ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof(struct SHTCTL));if (ctl == 0) {goto err;}ctl->vram = vram;ctl->xsize = xsize;ctl->ysize = ysize;// 一个 sheet 都没有ctl->top = -1; for (i = 0; i < MAX_SHEETS; i++) {// 标记为未使用ctl->sheets0[i].flags = 0;}err:return ctl;
}

【2】取得新生成的未使用图层sheet_alloc:

/*** @return struct SHEET* 获得新生成的未使用的图层 : 0 所有 SHEET 都在被使用*/
struct SHEET *sheet_alloc(struct SHTCTL *ctl){struct SHEET * sht;int i;for (i = 0; i < MAX_SHEETS; i++) {if (ctl->sheets0[i].flags == 0) {sht = &ctl->sheets0[i];sht->flags = SHEET_USE;// 标记为隐藏sht->height = -1;return sht;}}return 0;
}

【3】设置图层缓冲区大小和透明色sheet_setbuf:

void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv)
{sht->buf = buf;sht->bxsize = xsize;sht->bysize = ysize;sht->col_inv = col_inv;return;
}

【4】设定底板高度sheet_updown:

void sheet_updown(struct SHTCTL *ctl, struct SHEET *sht, int height){int h, old = sht->height;/* 边界判断 */if (height < -1) {height = -1;}if (height > ctl->top + 1) {height = ctl->top + 1;}sht->height = height;/* 比以前的高度低 */if (height < old) {if(height >= 0) {// 把 height - old 之间的部分向上提for (h = old; h > height; h--) {ctl->sheets[h] = ctl->sheets[h - 1];ctl->sheets[h]->height = h;}ctl->sheets[height] = sht;} else {if (ctl->top > old) {// 处于隐藏图层,把上面的部分降下来覆盖for (h = old; h < ctl->top; h++) {ctl->sheets[h] = ctl->sheets[h + 1];ctl->sheets[h]->height = h;}}ctl->top--;}sheet_refresh(ctl);} else if (height > old) {/* 比以前的高度要高 */if (old >= 0) {// 把 old - height 之间的图层往下挪for (h = old; h < height; h++) {ctl->sheets[h] = ctl->sheets[h + 1];ctl->sheets[h]->height = h;}ctl->sheets[height] = sht;} else {// 变成显示状态for (h = ctl->top; h >= height; h--) {ctl->sheets[h + 1] = ctl->sheets[h];ctl->sheets[h + 1]->height = h + 1;}ctl->sheets[height] = sht;ctl->top++; }sheet_refresh(ctl);} return;
}

【5】刷新图层sheet_refresh(就是将从下到上将透明以外的像素复制到VRAM中):

void sheet_refresh(struct SHTCTL *ctl){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;c = buf[by * sht->bxsize + bx];if (c != sht->col_inv) {vram[vy * ctl->xsize + vx] = c;}}}}return;
}

【6】上下左右滑动图层的函数sheet_slide:

void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0){sht->vx0 = vx0;sht->vy0 = vy0;if (sht->height >= 0) {// 没有隐藏就更新sheet_refresh(ctl);}return;
}

【7】释放已用内存的函数sheet_free:

void sheet_free(struct SHTCTL *ctl, struct SHEET *sht){if (sht->height >= 0) {sheet_updown(ctl, sht, -1);}sht->flags = 0;return;
}

【8】至此,关于图层的操作函数已经准备好,在主函数中调用他们:

#include "bootpack.h"
#include <stdio.h>void HariMain(void)
{struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;char s[40], keybuf[32], mousebuf[128];int mx, my, i;unsigned int memtotal;struct MOUSE_DEC mdec;struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;struct SHTCTL *shtctl;struct SHEET *sht_back, *sht_mouse;unsigned char *buf_back, buf_mouse[256];init_gdtidt();init_pic();io_sti(); fifo8_init(&keyfifo, 32, keybuf);fifo8_init(&mousefifo, 128, mousebuf);io_out8(PIC0_IMR, 0xf9); io_out8(PIC1_IMR, 0xef); init_keyboard();enable_mouse(&mdec);memtotal = memtest(0x00400000, 0xbfffffff);memman_init(memman);memman_free(memman, 0x00001000, 0x0009e000); memman_free(memman, 0x00400000, memtotal - 0x00400000);init_palette();shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);sht_back  = sheet_alloc(shtctl);sht_mouse = sheet_alloc(shtctl);buf_back  = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);// 没有背景色sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); // 透明色号 99sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99);init_screen8(buf_back, binfo->scrnx, binfo->scrny);init_mouse_cursor8(buf_mouse, 99);sheet_slide(shtctl, sht_back, 0, 0);// 按显示在画面中央来计算坐标mx = (binfo->scrnx - 16) / 2; my = (binfo->scrny - 28 - 16) / 2;sheet_slide(shtctl, sht_mouse, mx, my);sheet_updown(shtctl, sht_back,  0);sheet_updown(shtctl, sht_mouse, 1);sprintf(s, "(%3d, %3d)", mx, my);putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s);sprintf(s, "memory %dMB   free : %dKB",memtotal / (1024 * 1024), memman_total(memman) / 1024);putfonts8_asc(buf_back, binfo->scrnx, 0, 32, COL8_FFFFFF, s);sheet_refresh(shtctl);for (;;) {io_cli();if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {io_stihlt();} else {if (fifo8_status(&keyfifo) != 0) {i = fifo8_get(&keyfifo);io_sti();sprintf(s, "%02X", i);boxfill8(buf_back, binfo->scrnx, COL8_008484,  0, 16, 15, 31);putfonts8_asc(buf_back, binfo->scrnx, 0, 16, COL8_FFFFFF, s);sheet_refresh(shtctl);} else if (fifo8_status(&mousefifo) != 0) {i = fifo8_get(&mousefifo);io_sti();if (mouse_decode(&mdec, i) != 0) {sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);if ((mdec.btn & 0x01) != 0) {s[1] = 'L';}if ((mdec.btn & 0x02) != 0) {s[3] = 'R';}if ((mdec.btn & 0x04) != 0) {s[2] = 'C';}boxfill8(buf_back, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);putfonts8_asc(buf_back, binfo->scrnx, 32, 16, COL8_FFFFFF, s);mx += mdec.x;my += mdec.y;if (mx < 0) {mx = 0;}if (my < 0) {my = 0;}if (mx > binfo->scrnx - 16) {mx = binfo->scrnx - 16;}if (my > binfo->scrny - 16) {my = binfo->scrny - 16;}sprintf(s, "(%3d, %3d)", mx, my);// 消坐标boxfill8(buf_back, binfo->scrnx, COL8_008484, 0, 0, 79, 15); // 写坐标putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s); // 包含更新sheet_slide(shtctl, sht_mouse, mx, my);}}}}
}

三 提高图层刷新速度

文中主要列出了以下几种提高图层刷新速度的办法,这边只做说明,具体的实现由于篇幅的限制,就不一一阐明了:

【1】之前的刷新会刷整块VRAM,即320*200,这边将刷新的区域可以控制在指定的范围之内,这样的话,刷新速度就会有显著提高。

【2】将刷新函数限定为在一定范围内的循环,减少不必要的循环次数,也可以提高刷新速度。

当然,肯定还有一些其他的优化程序的方法,如果有兴趣的话可以思考一下。

【操作系统】30天自制操作系统--(9)叠加处理相关推荐

  1. 为什么《30天自制操作系统》封面中的猫是两只尾巴

    刚刚在一社区,发了一贴,被指出一问题,询一高人,得一答案.这便是我没有关注到的封面上的那只猫,我想这也是很多读者没有关注到的.因为在我微博的200转发贴中,并没有人提到封面中的猫为何有两只尾巴.于是咨 ...

  2. 发布在《30天自制操作系统》之前的帮助阅读贴

    说明:这是8月15日即将上市的一本新书,本文的摘选也可以命名为<30天自制操作系统>上市之前必读.本书幽默,有趣,可以说是技术书里的幽默书,让您读起来绝对不会感到乏味.在本书上市之前,您一 ...

  3. 《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!

    <30天自制操作系统>笔记(01)--hello bitzhuwei's OS! 最初的OS代码 1 ; hello-os 2 ; TAB=4 3 4 ORG 0x7c00 ; 指明程序的 ...

  4. 写在《30天自制操作系统》上市之前

       这本<30天自制操作系统>马上就要在各大书店和网上商城全面上架了,作为本书的4位译者之一,我负责翻译了本书约三分之二的内容.这是我参与翻译的第一本译著,我感到很激动也很紧张,因为我知 ...

  5. 《30天自制操作系统》笔记(04)——显示器256色

    <30天自制操作系统>笔记(04)--显示器256色 进度回顾 从最开始的(01)篇到上一篇为止,已经解决了开发环境问题和OS项目的顶层设计问题. 本篇做一个小练习:设置显卡显示256色. ...

  6. 《30天自制操作系统》学习笔记--第好多天

    之前看<30天自制操作系统>,参考而成,和书中系统并不完全一致,是在原有基础上按照自己的习惯而成,由于水平和工作原因,未完成内存管理和文件系统,有兴趣者可以通过以下网址https://gi ...

  7. 由《30天自制操作系统》引发的漫画创作

    大家可还记得<30天自制操作系统>的封面上的那只猫吗?记得当时,在果壳网有人问,为何这只猫长了两只尾巴呢,延着这条线,我把这本书捧上了展示的舞台.事隔四个多月,我又重提此书. 这本经我手宣 ...

  8. 30天自制操作系统——第二十三天窗口操作

    窗口及输入切换 我们先来实现用键盘切换窗口,按下F11键,将最下面的窗口移动到最上面,这里F11按键的编码为0x57. bootpack.c节选: void HariMain(void) {(略)fo ...

  9. 30天自制操作系统-初体验

    最近在图书馆翻阅关于操作系统的书籍,看到川和秀实的自制操作系统决定也动手尝试一下,这本书书名就叫做30天自制操作系统.首先还是附上光盘镜像的获取地址吧.30天自制操作系统光盘镜像ISO完整版下载 - ...

最新文章

  1. 后台获取视图对应的字符串
  2. linux 网络错误 nf_conntrack: table full, dropping packet. 路由跟踪表满
  3. 理论修炼之ETCD,高一致性Key-Value服务提供者中的佼佼者
  4. jdk11 后用的指定编码格式,读取文件
  5. linux忘记mysql密码_Linux下忘记Mysql密码的找回方法(图)
  6. [python教程入门学习]使用Python六步制作小鸟管道游戏(附源码)
  7. 联想Y580黑苹果安装
  8. 基于UDP的网络对战五子棋
  9. 设计师点评互联网巨头Logo
  10. K-Means聚类算法原理及实现
  11. 工欲善其事,必先利其器——学会不将就,让自己事半功倍!
  12. 单独使用Quartz 2.1.7 时Job属性Spring无法注入
  13. 【hadoop生态之ZooKeeper】第一章Zookeeper概述【笔记+代码】
  14. cad简化螺纹lisp_二维螺纹的AutoLISP工具
  15. si,di,ds,es寄存器
  16. 视频通话和聊天工具Jitsi
  17. 根据图片名字生成文件夹并归类+批量重命名照片名
  18. xbox one怎样设置html5,如何安装设置XBOX ONE?XBOX ONE怎么用?
  19. 金融服务(银行证券机构方向)etl批量作业集群统一调度平台搭建
  20. 软件著作权审查时间、软件导刊审稿周期、计算机工程与应用审稿周期、计算机技术与发展审稿周期、电子测量与仪器学报审稿周期

热门文章

  1. mac系统双开应用(QQ、微信)
  2. 关于《基于eclipse的android项目实战—博学谷》的问题,为了这个差点疯了
  3. 服务器如何防御攻击,有哪些方法
  4. 设置 IIS下虚拟目录或应用程序不继承主站点的web.config
  5. wifi模块和云端服务器的协议,wifi模块连接云端服务器的尝试(esp8266连thingSpeak)
  6. 工具类分享--便捷地改变字体样式
  7. OneNote脱机文件的新旧电脑间转移(从win10到win11)
  8. 计算机网络ospf实验报告,中山大学《计算机网络实验报告》10-OSPF实验.pdf
  9. 财富自由:金钱、注意力、时间、认知,你会怎么排?
  10. 一维数组与对象深拷贝的几种方法(指数组、对象中均无嵌套)