Optimize scrolling to not redraw tiles when not needed
This commit is contained in:
parent
c2d648d284
commit
d676190aaf
98
testbed.c
98
testbed.c
|
@ -391,7 +391,7 @@ int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int
|
||||||
unsigned int *rp = gp + planeStride;
|
unsigned int *rp = gp + planeStride;
|
||||||
unsigned int *ip = rp + planeStride;
|
unsigned int *ip = rp + planeStride;
|
||||||
unsigned int *mp = ip + planeStride;
|
unsigned int *mp = ip + planeStride;
|
||||||
unsigned char bv, gv, rv, iv;
|
unsigned int bv, gv, rv, iv;
|
||||||
|
|
||||||
if (meta.width > MAX_WIDTH || (meta.width % 16) != 0 || planes < 4 || planes > 5) {
|
if (meta.width > MAX_WIDTH || (meta.width % 16) != 0 || planes < 4 || planes > 5) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -412,7 +412,7 @@ int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int
|
||||||
int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4;
|
int gpair = (pixelpair & 0x02) >> 1 | (pixelpair & 0x20) >> 4;
|
||||||
int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5;
|
int rpair = (pixelpair & 0x04) >> 2 | (pixelpair & 0x40) >> 5;
|
||||||
int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6;
|
int ipair = (pixelpair & 0x08) >> 3 | (pixelpair & 0x80) >> 6;
|
||||||
int shift = (3 - (ipixelpair % 4)) << 1;
|
int shift = (7 - (ipixelpair % 8)) << 1;
|
||||||
|
|
||||||
bv |= bpair << shift;
|
bv |= bpair << shift;
|
||||||
gv |= gpair << shift;
|
gv |= gpair << shift;
|
||||||
|
@ -425,7 +425,8 @@ int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int
|
||||||
*rp++ = rv;
|
*rp++ = rv;
|
||||||
*ip++ = iv;
|
*ip++ = iv;
|
||||||
if (planes == 5) {
|
if (planes == 5) {
|
||||||
*mp++ = bv & gv & rv & iv;
|
iv = ~(bv & gv & rv & iv);
|
||||||
|
*mp++ = iv;
|
||||||
}
|
}
|
||||||
bv = gv = rv = iv = 0;
|
bv = gv = rv = iv = 0;
|
||||||
}
|
}
|
||||||
|
@ -448,6 +449,18 @@ int tifLoad(FILE *f, TifImageMeta_t meta, unsigned int *planeBuf, int maxY, int
|
||||||
|
|
||||||
/*** T I L E S ***/
|
/*** T I L E S ***/
|
||||||
|
|
||||||
|
// Tiles are 16x16 bitmaps, stored as arrays of words.
|
||||||
|
// Each tile has 4 or 5 planes (depending on whether it is a tile or sprite)
|
||||||
|
// which are stored adjacant to each other; ie. a 16-word array of blue,
|
||||||
|
// followed by a 16-word array of green, etc.
|
||||||
|
// Tiles in RAM are stored byte-swapped to aid in fast bit-shifting, and must
|
||||||
|
// be byte-swapped before being written to video memory.
|
||||||
|
|
||||||
|
// Because bit-shifting operations happen on little-endian words:
|
||||||
|
// 01234567 89ABCDEF << 3 => 34567XXX BCDEF012
|
||||||
|
// which is wrong. So instead we do:
|
||||||
|
// 89ABCDEF 01234567 << 3 => BCDEFXXX 3456789A byteswap => 3456789A BCDEFXXX
|
||||||
|
|
||||||
#define PAGE_TILES_W 21
|
#define PAGE_TILES_W 21
|
||||||
#define PAGE_TILES_H 13
|
#define PAGE_TILES_H 13
|
||||||
#define PAGE_TILES_COUNT (PAGE_TILES_H * PAGE_TILES_W)
|
#define PAGE_TILES_COUNT (PAGE_TILES_H * PAGE_TILES_W)
|
||||||
|
@ -503,6 +516,7 @@ void loadMap(unsigned char *map, unsigned int w, unsigned int h) {
|
||||||
screen.map = map;
|
screen.map = map;
|
||||||
screen.w = w;
|
screen.w = w;
|
||||||
screen.h = h;
|
screen.h = h;
|
||||||
|
memset(screen.dirty, D_BGTILE, PAGE_TILES_COUNT * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int prepareBuffer(int pageX, int pageY) {
|
int prepareBuffer(int pageX, int pageY) {
|
||||||
|
@ -523,6 +537,7 @@ int prepareBuffer(int pageX, int pageY) {
|
||||||
|
|
||||||
void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int yStart) {
|
void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int yStart) {
|
||||||
unsigned int *buf, *mask;
|
unsigned int *buf, *mask;
|
||||||
|
unsigned int maskval;
|
||||||
int y, h, plane;
|
int y, h, plane;
|
||||||
if (pageX < 0 || pageY < 0 ||
|
if (pageX < 0 || pageY < 0 ||
|
||||||
pageX >= PAGE_TILES_W || pageY >= PAGE_TILES_H ||
|
pageX >= PAGE_TILES_W || pageY >= PAGE_TILES_H ||
|
||||||
|
@ -532,19 +547,20 @@ void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = screen.buffer[prepareBuffer(pageX, pageY)];
|
buf = screen.buffer[prepareBuffer(pageX, pageY)];
|
||||||
/* if (yStart < 0) {
|
if (yStart < 0) {
|
||||||
sprite = &sprite[-yStart];
|
sprite = &sprite[-yStart];
|
||||||
h = yStart + 16;
|
h = yStart + 16;
|
||||||
} else {
|
} else {
|
||||||
buf = &buf[yStart];
|
buf = &buf[yStart];
|
||||||
h = 16 - yStart;
|
h = 16 - yStart;
|
||||||
}
|
}
|
||||||
mask = &sprite[16 * 4];
|
mask = &sprite[BUF_WSTRIDE * 4];
|
||||||
if (shift < 0) {
|
if (shift < 0) {
|
||||||
shift = -shift;
|
shift = -shift;
|
||||||
for (plane = 0; plane < 4; plane ++) {
|
for (plane = 0; plane < 4; plane ++) {
|
||||||
for (y = 0; y < h; y ++) {
|
for (y = 0; y < h; y ++) {
|
||||||
buf[y] = (buf[y] & ~(mask[y] << shift)) | (sprite[y] << shift);
|
maskval = mask[y] << shift;
|
||||||
|
buf[y] = (buf[y] & ~maskval) | ((sprite[y] << shift) & maskval);
|
||||||
}
|
}
|
||||||
sprite += BUF_WSTRIDE;
|
sprite += BUF_WSTRIDE;
|
||||||
buf += BUF_WSTRIDE;
|
buf += BUF_WSTRIDE;
|
||||||
|
@ -552,12 +568,13 @@ void drawSpriteToBuf(unsigned int *sprite, int pageX, int pageY, int shift, int
|
||||||
} else {
|
} else {
|
||||||
for (plane = 0; plane < 4; plane ++) {
|
for (plane = 0; plane < 4; plane ++) {
|
||||||
for (y = 0; y < h; y ++) {
|
for (y = 0; y < h; y ++) {
|
||||||
buf[y] = (buf[y] & ~(mask[y] >> shift)) | (sprite[y] >> shift);
|
maskval = mask[y] >> shift;
|
||||||
|
buf[y] = (buf[y] & ~maskval) | ((sprite[y] >> shift) & maskval);
|
||||||
}
|
}
|
||||||
sprite += BUF_WSTRIDE;
|
sprite += BUF_WSTRIDE;
|
||||||
buf += BUF_WSTRIDE;
|
buf += BUF_WSTRIDE;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawSprite(unsigned int *sprite, int x, int y) {
|
void drawSprite(unsigned int *sprite, int x, int y) {
|
||||||
|
@ -572,15 +589,32 @@ void drawSprite(unsigned int *sprite, int x, int y) {
|
||||||
drawSpriteToBuf(sprite, pageX + 1, pageY + 1, pageOffsetX - 16, pageOffsetY - 16);
|
drawSpriteToBuf(sprite, pageX + 1, pageY + 1, pageOffsetX - 16, pageOffsetY - 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scroll(int x, int y) {
|
void scroll(int newX, int newY) {
|
||||||
x = min(max(x, 0), (screen.w << 4) - 320);
|
newX = min(max(newX, 0), (screen.w << 4) - 320);
|
||||||
y = min(max(y, 0), (screen.h << 4) - 176);
|
newY = min(max(newY, 0), (screen.h << 4) - 176);
|
||||||
if ((screen.scrollX & 0xfff0) != (x & 0xfff0) ||
|
if ((screen.scrollX & 0xfff0) != (newX & 0xfff0) ||
|
||||||
(screen.scrollY & 0xfff0) != (y & 0xfff0)) {
|
(screen.scrollY & 0xfff0) != (newY & 0xfff0)) {
|
||||||
memset(screen.dirty, D_BGTILE, 2 * PAGE_TILES_COUNT);
|
int mapX, mapY;
|
||||||
|
unsigned char page;
|
||||||
|
for (page = 0; page < 2; page ++) {
|
||||||
|
int mapOffsetOld = (screen.scrollX >> 4) + ((screen.scrollY >> 4) * screen.w);
|
||||||
|
int mapOffsetNew = (newX >> 4) + ((newY >> 4) * screen.w);
|
||||||
|
unsigned char *dirty = screen.dirty[page];
|
||||||
|
for (mapY = 0; mapY < PAGE_TILES_H; mapY ++) {
|
||||||
|
for (mapX = 0; mapX < PAGE_TILES_W; mapX ++) {
|
||||||
|
if (*dirty != D_NOTHING ||
|
||||||
|
screen.map[mapOffsetOld + mapX] != screen.map[mapOffsetNew + mapX]) {
|
||||||
|
*dirty = D_BGTILE;
|
||||||
|
}
|
||||||
|
dirty ++;
|
||||||
|
}
|
||||||
|
mapOffsetNew += screen.w;
|
||||||
|
mapOffsetOld += screen.w;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
screen.scrollX = x;
|
screen.scrollX = newX;
|
||||||
screen.scrollY = y;
|
screen.scrollY = newY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawScreen() {
|
void drawScreen() {
|
||||||
|
@ -591,7 +625,7 @@ void drawScreen() {
|
||||||
unsigned int drawOffset = screen.pageOffset[screen.currentPage];
|
unsigned int drawOffset = screen.pageOffset[screen.currentPage];
|
||||||
unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE);
|
unsigned int scrollOffset = drawOffset + (offsetX >> 3) + (offsetY * PAGE_STRIDE);
|
||||||
unsigned char *dirty = screen.dirty[screen.currentPage];
|
unsigned char *dirty = screen.dirty[screen.currentPage];
|
||||||
unsigned int x, y, di, plane;
|
unsigned int x, y, di, plane, bmp;
|
||||||
|
|
||||||
setAllPlanes();
|
setAllPlanes();
|
||||||
setWriteMode(1);
|
setWriteMode(1);
|
||||||
|
@ -600,7 +634,9 @@ void drawScreen() {
|
||||||
for (y = startY; y < startY + PAGE_TILES_H; y ++) {
|
for (y = startY; y < startY + PAGE_TILES_H; y ++) {
|
||||||
for (x = startX; x < startX + PAGE_TILES_W; x ++) {
|
for (x = startX; x < startX + PAGE_TILES_W; x ++) {
|
||||||
if (dirty[di++] == D_BGTILE) {
|
if (dirty[di++] == D_BGTILE) {
|
||||||
blitTile(screen.tilesOffset + screen.map[x + (y * screen.w)], drawOffset);
|
blitTile(
|
||||||
|
screen.tilesOffset + (screen.map[x + (y * screen.w)] << 5),
|
||||||
|
drawOffset);
|
||||||
}
|
}
|
||||||
drawOffset += 2;
|
drawOffset += 2;
|
||||||
}
|
}
|
||||||
|
@ -612,7 +648,8 @@ void drawScreen() {
|
||||||
for (di = screen.firstBuffer; di != screen.nextBuffer; di = nextBufferIndex(di)) {
|
for (di = screen.firstBuffer; di != screen.nextBuffer; di = nextBufferIndex(di)) {
|
||||||
drawOffset = screen.bufferOffset[di] >> 1;
|
drawOffset = screen.bufferOffset[di] >> 1;
|
||||||
for (y = 0; y < 16; y ++) {
|
for (y = 0; y < 16; y ++) {
|
||||||
WVID[drawOffset] = screen.buffer[di][y + (BUF_WSTRIDE * plane)];
|
bmp = screen.buffer[di][y + (BUF_WSTRIDE * plane)];
|
||||||
|
WVID[drawOffset] = (bmp << 8) | (bmp >> 8);
|
||||||
drawOffset += PAGE_STRIDE >> 1;
|
drawOffset += PAGE_STRIDE >> 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -630,9 +667,10 @@ void drawScreen() {
|
||||||
#define NUM_TILES 128
|
#define NUM_TILES 128
|
||||||
#define NUM_SPRITES 64
|
#define NUM_SPRITES 64
|
||||||
#define OFF_TILES 0x4840
|
#define OFF_TILES 0x4840
|
||||||
|
#define TILE_STRIDE 64
|
||||||
unsigned int tiles[NUM_TILES][4*16];
|
#define SPRITE_STRIDE 80
|
||||||
unsigned int sprites[NUM_SPRITES][5*16];
|
unsigned int tiles[NUM_TILES * TILE_STRIDE];
|
||||||
|
unsigned int sprites[NUM_SPRITES * SPRITE_STRIDE];
|
||||||
|
|
||||||
|
|
||||||
unsigned char map[10000];
|
unsigned char map[10000];
|
||||||
|
@ -643,7 +681,7 @@ void fillMap() {
|
||||||
|
|
||||||
for (y = 0; y < 100; y ++) {
|
for (y = 0; y < 100; y ++) {
|
||||||
for (x = 0; x < 100; x ++) {
|
for (x = 0; x < 100; x ++) {
|
||||||
map[x + (y * 100)] = (((x + y + z) >> 2) % 4) << 5;
|
map[x + (y * 100)] = ((x + y + z) >> 2) % 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -665,8 +703,8 @@ void game_init() {
|
||||||
|
|
||||||
f = fopen("TILES.TIF", "rb");
|
f = fopen("TILES.TIF", "rb");
|
||||||
meta = tifLoadMeta(f);
|
meta = tifLoadMeta(f);
|
||||||
tifLoadEGA(f, meta, OFF_TILES, NUM_TILES * 16, 16);
|
|
||||||
tifLoad(f, meta, tiles, NUM_TILES * 16, 16, 4);
|
tifLoad(f, meta, tiles, NUM_TILES * 16, 16, 4);
|
||||||
|
tifLoadEGA(f, meta, OFF_TILES, NUM_TILES * 16, 16);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
f = fopen("SPRITE.TIF", "rb");
|
f = fopen("SPRITE.TIF", "rb");
|
||||||
|
@ -691,13 +729,13 @@ int main() {
|
||||||
|
|
||||||
while (!keyPressed(K_ESC)) {
|
while (!keyPressed(K_ESC)) {
|
||||||
|
|
||||||
if (keyPressed(K_LEFT)) x -= 1;
|
if (keyPressed(K_LEFT)) x -= 3;
|
||||||
if (keyPressed(K_RIGHT)) x += 1;
|
if (keyPressed(K_RIGHT)) x += 3;
|
||||||
if (keyPressed(K_UP)) y -= 1;
|
if (keyPressed(K_UP)) y -= 3;
|
||||||
if (keyPressed(K_DOWN)) y += 1;
|
if (keyPressed(K_DOWN)) y += 3;
|
||||||
scroll(x - 152, y - 90);
|
scroll(x - 152, y - 90);
|
||||||
drawSprite(sprites[0], 50, 50);
|
drawSprite(&sprites[0 * SPRITE_STRIDE], 50, 50);
|
||||||
drawSprite(sprites[1], x, y);
|
drawSprite(&sprites[1 * SPRITE_STRIDE], x, y);
|
||||||
drawScreen();
|
drawScreen();
|
||||||
|
|
||||||
z++;
|
z++;
|
||||||
|
|
BIN
testbed.exe
BIN
testbed.exe
Binary file not shown.
Loading…
Reference in a new issue