From 661f470cc8197f643a2ab36c35fb0630f31023aa Mon Sep 17 00:00:00 2001 From: davidovski Date: Sun, 23 Jul 2023 23:45:47 +0200 Subject: optimise chunk loading and redrawing --- src/tiled.c | 40 +++++++++++++++++--------- src/tiled.h | 8 +++--- src/tiledmap.c | 90 +++++++++++++--------------------------------------------- src/tiledmap.h | 4 +-- 4 files changed, 52 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/tiled.c b/src/tiled.c index b90aea7..436029b 100644 --- a/src/tiled.c +++ b/src/tiled.c @@ -14,15 +14,19 @@ void updateCamera(Tiled * tiled) { if (IsKeyDown(KEY_W)) tiled->zoom += tiled->zoom * 0.01f; if (IsKeyDown(KEY_S)) tiled->zoom -= tiled->zoom * 0.01f; + tiled->chunkOffset[2] = tiled->chunkOffset[0]; + tiled->chunkOffset[3] = tiled->chunkOffset[1]; + tiled->chunkOffset[0] = tiled->offset.x / tiled->tiledMap.chunkWidth; tiled->chunkOffset[1] = tiled->offset.y / tiled->tiledMap.chunkHeight; tiled->renderOffset.x = tiled->offset.x - tiled->chunkOffset[0]*tiled->tiledMap.chunkWidth; tiled->renderOffset.y = tiled->offset.y - tiled->chunkOffset[1]*tiled->tiledMap.chunkHeight; - // TODO only do this when chunk offset has changed // TODO unload chunks when they are no longer visible - redrawTiledMap(*tiled); + if (tiled->chunkOffset[0] != tiled->chunkOffset[2] + || tiled->chunkOffset[1] != tiled->chunkOffset[3]) + redrawTiledMap(*tiled); } void updateTiledCamera(Tiled *tiled) { @@ -52,29 +56,35 @@ Vector2 translateTiledPosition(Tiled tiled, Vector2 screenPos) { Vector2 translateTiledScreenPosition(Tiled tiled, Vector2 tiledPos) { return (Vector2) { - (tiledPos.x + tiled.renderOffset.x + tiled.chunkOffset[0]*tiled.tiledMap.chunkWidth) * tiled.zoom, - (tiledPos.y + tiled.renderOffset.y + tiled.chunkOffset[1]*tiled.tiledMap.chunkHeight) * tiled.zoom + (tiledPos.x + tiled.offset.x) * tiled.zoom, + (tiledPos.y + tiled.offset.y) * tiled.zoom }; } -Tile getOffsetTile(TiledMap * tiledMap, int chunkOffset[2], int x, int y) { - return getChunkedTile(tiledMap, - x - chunkOffset[0]*tiledMap->chunkWidth, - y - chunkOffset[1]*tiledMap->chunkHeight); -} - void redrawTile(Tiled tiled, int x, int y) { + int areaX = x + tiled.chunkOffset[0]*tiled.tiledMap.chunkWidth; + int areaY = tiled.renderArea[1] - y - tiled.chunkOffset[1]*tiled.tiledMap.chunkHeight - 1; + + Tile v = getChunkedTile(&tiled.tiledMap, x, y); + BeginTextureMode(tiled.tilemapTexture); - Tile v = getOffsetTile(&tiled.tiledMap, tiled.chunkOffset, x, y); - DrawPixel(x, tiled.renderArea[1] - y - 1, (Color){ v, 0, 0, 255 }); + DrawPixel(areaX, areaY, (Color){ v, 0, 0, 255 }); EndTextureMode(); } void redrawTiledMap(Tiled tiled) { + // TODO since we have to do this every time a chunk is loaded, maybe there is a better way + int realX, realY; + Tile v; + BeginTextureMode(tiled.tilemapTexture); for (int y = 0; y < tiled.renderArea[1]; y++) { for (int x = 0; x < tiled.renderArea[0]; x++) { - Tile v = getOffsetTile(&tiled.tiledMap, tiled.chunkOffset, x, y); + realX = x - tiled.chunkOffset[0]*tiled.tiledMap.chunkWidth; + realY = y - tiled.chunkOffset[1]*tiled.tiledMap.chunkHeight; + + v = getChunkedTile(&tiled.tiledMap, realX, realY); + DrawPixel(x, tiled.renderArea[1] - y - 1, (Color){ v, 0, 0, 255 }); } } @@ -88,9 +98,11 @@ Tiled initTiled(TiledMap tiledMap) { tiled.offset = (Vector2) {0, 0}; tiled.zoom = 64; - // TODO renderArea is obsolete, should be visible map size tiled.renderArea[0] = tiledMap.chunkWidth * RENDER_DISTANCE; tiled.renderArea[1] = tiledMap.chunkHeight * RENDER_DISTANCE; + + printf("Render area %dx%d\n", tiled.renderArea[0], tiled.renderArea[1]); + tiled.targetTexture = LoadRenderTexture(1, 1); tiled.tilemapTexture = LoadRenderTexture(tiled.renderArea[0], tiled.renderArea[1]); diff --git a/src/tiled.h b/src/tiled.h index de469be..ae8fcc5 100644 --- a/src/tiled.h +++ b/src/tiled.h @@ -5,19 +5,19 @@ #define SCREEN_W 1280 #define SCREEN_H 720 -#define RENDER_DISTANCE 16 +#define RENDER_DISTANCE 4 -typedef struct Tiled { +typedef struct { TiledMap tiledMap; float zoom; - + // main viewport offset Vector2 offset; // offset passed to shader for rendering Vector2 renderOffset; // offset used to calculate which chunks to render - int chunkOffset[2]; + int chunkOffset[4]; int atlasSize[2]; int renderArea[2]; diff --git a/src/tiledmap.c b/src/tiledmap.c index ea587cc..bb5a1fd 100644 --- a/src/tiledmap.c +++ b/src/tiledmap.c @@ -4,56 +4,7 @@ #include #include "tiledmap.h" - -const int endian = 1; -#define is_bigendian() ( (*(char*)&endian) == 0 ) - -void textureFromPixels(Texture2D *texOut, Color *pixels, int width, int height) { - Image checkedIm = { - .data = pixels, - .width = width, - .height = height, - .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, - .mipmaps = 1 - }; - - *texOut = LoadTextureFromImage(checkedIm); -} - - -//! read a big endian bytes from file -int readb(char * out, size_t noBytes, FILE * file) { - if (!fread(out, (size_t)1, (size_t) noBytes, file)) - return 1; - - if (is_bigendian()) - return 0; - - int tmp; - // reverse byte order - for(int i = 0; i < noBytes/2; i++) { - tmp = out[i]; - out[i] = out[noBytes-i-1]; - out[noBytes-i-1] = tmp; - } - - return 0; -} - -int writeb(char * in, size_t noBytes, FILE * file) { - if (!is_bigendian()) { - int tmp; - // reverse byte order - for(int i = 0; i < noBytes/2; i++) { - tmp = in[i]; - in[i] = in[noBytes-i-1]; - in[noBytes-i-1] = tmp; - } - - } - - return fwrite(in, (size_t)1, (size_t) noBytes, file); -} +#include "tiledio.h" void buildChunkTree(TiledMap *tiledMap) { // initialise chunk tree @@ -143,7 +94,6 @@ void unloadChunk(TiledMap * tiledMap, CachedChunk * cached) { //! load a chunk into the cache and return it CachedChunk * loadChunk(TiledMap * tiledMap, int x, int y) { - // TODO add caching for this size_t chunkSizeBytes = tiledMap->chunkWidth * tiledMap->chunkHeight; @@ -157,7 +107,6 @@ CachedChunk * loadChunk(TiledMap * tiledMap, int x, int y) { cached->chunk = malloc(chunkSizeBytes); fseek(tiledMap->file, cached->filePos, SEEK_SET); fread(cached->chunk, 1, chunkSizeBytes, tiledMap->file); - printf("loading chunk %d,%d, from %ld\n", x, y, cached->filePos); } return cached; @@ -184,46 +133,49 @@ CachedChunk * createChunk(TiledMap *tiledMap, int x, int y, Chunk chunk) { return cached; } -CachedChunk * createEmptyChunk(TiledMap * tiledMap, int x, int y) { +CachedChunk * createEmptyChunkAt(TiledMap * tiledMap, int x, int y) { Chunk chunk = calloc(tiledMap->chunkWidth*tiledMap->chunkHeight, 1); - return createChunk(tiledMap, x, y, chunk); + return createChunk(tiledMap, x / tiledMap->chunkWidth, y / tiledMap->chunkHeight, chunk); } -Tile getChunkedTile(TiledMap *tiledMap, int x, int y) { - // TODO put this calculation in function +CachedChunk * loadChunkPosition(TiledMap *tiledMap, int x, int y, int * index) { int inChunkX = x % tiledMap->chunkWidth; int inChunkY = y % tiledMap->chunkHeight; int chunkX = (x - inChunkX) / tiledMap->chunkWidth; int chunkY = (y - inChunkY) / tiledMap->chunkHeight; + *index = inChunkY * tiledMap->chunkWidth + inChunkX; + return loadChunk(tiledMap, chunkX, chunkY); +} + +Tile getChunkedTile(TiledMap *tiledMap, int x, int y) { if (x < 0 || y < 0) return 0; - CachedChunk * cached = loadChunk(tiledMap, chunkX, chunkY); + int index; + CachedChunk * cached = loadChunkPosition(tiledMap, x, y, &index); + if (cached == NULL) return 0; if (cached->chunk == NULL) return 0; - Tile v = cached->chunk[inChunkY * tiledMap->chunkWidth + inChunkX]; - return v; + return cached->chunk[index]; } Tile setChunkedTile(TiledMap * tiledMap, int x, int y, Tile value) { - int inChunkX = x % tiledMap->chunkWidth; - int inChunkY = y % tiledMap->chunkHeight; - int chunkX = (x - inChunkX) / tiledMap->chunkWidth; - int chunkY = (y - inChunkY) / tiledMap->chunkHeight; + if (x < 0 || y < 0) + return 0; + + int index; + CachedChunk * cached = loadChunkPosition(tiledMap, x, y, &index); - CachedChunk * cached = loadChunk(tiledMap, chunkX, chunkY); if (cached == NULL) - cached = createEmptyChunk(tiledMap, chunkX, chunkY); + cached = createEmptyChunkAt(tiledMap, x, y); - cached->chunk[inChunkY * tiledMap->chunkWidth + inChunkX] = value; + cached->chunk[index] = value; - // TODO do this when unloading - //commitChunk(tiledMap, cached); return value; } @@ -244,8 +196,6 @@ void writeTiledMapHeader(TiledMap tiledMap) { writeb((char *) &tiledMap.atlasSize[1], 4, file); fwrite(tiledMap.atlasData, 1, atlasSizeBytes, file); - // since chunks are already directly written here, do not write anything else - // TODO when caching, commit everything left in cache here } TiledMap openNewTiledMap(char * filename, Image atlas, int tileSize, int chunkWidth, int chunkHeight, int width, int height) { diff --git a/src/tiledmap.h b/src/tiledmap.h index 972a74d..7b819a2 100644 --- a/src/tiledmap.h +++ b/src/tiledmap.h @@ -6,12 +6,12 @@ typedef unsigned char Tile; typedef Tile * Chunk; -typedef struct CachedChunk { +typedef struct { long filePos; Chunk chunk; } CachedChunk; -typedef struct ChunkedTiledMap { +typedef struct { FILE * file; int chunkWidth; int chunkHeight; -- cgit v1.2.1