1.内存管理(续)
第九天的程序以一字节为单位,对内存进行分配和释放,但是这样在执行多次后,内存会成为一小块一小块的,同时frees将不够用,所以要以0x1000字节为单位向上取舍。
向下取舍:对与10进位,向下取舍就是直接舍去低位;对于二进制来说,向下取舍可以直接与0进行&操作;
向上取舍:i=i&(0x10000000-向下舍入单位)
2.图层叠加处理
图层结构体:
#define MAX_SHEETS 256
struct SHEET {
unsigned char *buf; /*记录图层上所描画内容的地址*/
int bxsize, bysize, vx0, vy0, col_inv, height, flags;
/*bxsize,bysize表示图层整体大小;vx0,vy0表示图层在画面上相对位置,col_inv表示透明色*/
};
图层控制器结构体:
#define MAX_SHEETS 256
struct SHTCTL {
unsigned char *vram; /*内存地址*/
int xsize, ysize, top; /*画面大小,顶层高度*/
struct SHEET *sheets[MAX_SHEETS]; /*记忆地址变的领域*/
struct SHEET sheets0[MAX_SHEETS]; /*用于存放准备的256个图层信息*/
};
用4k大小分配内存给图层控制器,并初始化:
/*memman为可用内存空间管理器,vram是显卡内存,xsize是画面尺寸*/
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;
ctl->top = -1; /* 没有图层呢 */
for (i = 0; i < MAX_SHEETS; i++) {
ctl->sheets0[i].flags = 0; /* 所有图层标记为未使用 */
}
err:
return ctl;
}
取得新生成的未使用图层,并将图层标记为1(使用):
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取得图层管理器ctl的i图层*/
sht->flags = SHEET_USE; /* 标记为正在使用 */
sht->height = -1; /* 隐藏 */
return sht;
}
}
return 0; /* 所有sheet都处于使用状态 */
}
设置图层的大小和透明颜色:
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;
图层变动后,设置图层的高度:
void sheet_updown(struct SHTCTL *ctl, struct SHEET *sht, int height)
{
int h, old = sht->height; /* 存储旧的高度信息 */
/* 如果指定高度过大或者过小,进行修正 */
if (height > ctl->top + 1) {
height = ctl->top + 1;
}
if (height < -1) {
height = -1;
}
sht->height = height; /* 设定高度 */
/* 下面主要进行sheets[]的重新排序 */
if (old > height) { /* 比以前低 */
if (height >= 0) {
/* 把中间的往上提 */
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 (old < height) { /*比以前高 */
if (old >= 0) {
/* 把中间的拉上去 */
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;
}
刷新图层控制器的所有图层(0~h):
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;
}
不改变高度,只滑动图层:
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;
}
释放图层:
void sheet_free(struct SHTCTL *ctl, struct SHEET *sht)
{
if (sht->height >= 0) {
sheet_updown(ctl, sht, -1); /* 如果图层处于显示状态,先隐藏 */
}
sht->flags = 0; /* 标为未使用 */
return;
}
bootpack.c在源文件中,自己看吧。
3.叠加处理提速(减少刷新区域)
3.1移动图层时, 只刷新图层移动前后所在两个区域:
void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0)
{
int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
sht->vx0 = vx0;
sht->vy0 = vy0;
if (sht->height >= 0) { /* 如果正在显示,则按图层新信息刷新画面 */
sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);
sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);
}
return;
}
刷新(vx0,vy0)~(vx1,vy1)这一区域的函数:
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;
}
刷新坐标所在图层的显示字符:
void sheet_refresh(struct SHTCTL *ctl, struct SHEET *sht, int bx0, int by0, int bx1, int by1)
{
if (sht->height >= 0) { /* 显示状态,就刷新 */
sheet_refreshsub(ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1);
}
return;
}
改变的updown()和bootpack.c查看源文件。
3.2减少判断次数
之前程序每个图层刷新时,都会判断——该图层所有像素,是否需要写入新数据?
改良成,只刷新:当所有图层与更新图层重合部分:
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
{
int h, bx, by, vx, vy, bx0, by0, bx1, by1;
unsigned char *buf, c, *vram = ctl->vram;
struct SHEET *sht;
for (h = 0; h <= ctl->top; h++) {
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;
}
}
}
}
return;
}