From 5ec62c0a2a0357a79f92b8bb37f67272e7f910ff Mon Sep 17 00:00:00 2001 From: davidovski Date: Sat, 22 Jul 2023 00:50:32 +0200 Subject: loading map data from chunks rather than tilelayout --- makefile | 5 ++- src/chunkedtiledmap.c | 114 ++++++++++++++++++++++++++++++++++++++++++++------ src/chunkedtiledmap.h | 14 +++++-- src/editor.c | 31 +++++++------- src/kdtree.c | 4 ++ src/kdtree.h | 3 ++ src/tiled.c | 47 ++++++--------------- src/tiled.h | 6 +-- src/tiledmap.c | 2 +- 9 files changed, 156 insertions(+), 70 deletions(-) diff --git a/makefile b/makefile index 28fbdab..928632f 100644 --- a/makefile +++ b/makefile @@ -3,6 +3,7 @@ FLAGS=-lm -lraylib -ggdb .DEFAULT_GOAL := editor -editor: src/*.c src/editor.c - ${CC} src/*.c -o editor ${FLAGS} +EDITOR_SOURCE=src/chunkedtiledmap.c src/editor.c src/kdtree.c src/tiled.c +editor: ${EDITOR_SOURCE} + ${CC} ${EDITOR_SOURCE} -o editor ${FLAGS} diff --git a/src/chunkedtiledmap.c b/src/chunkedtiledmap.c index ce6be57..a3019af 100644 --- a/src/chunkedtiledmap.c +++ b/src/chunkedtiledmap.c @@ -2,10 +2,26 @@ #include #include #include -#include #include "chunkedtiledmap.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)) @@ -41,17 +57,25 @@ int writeb(char * in, size_t noBytes, FILE * file) { } void buildChunkTree(ChunkedTiledMap *tiledMap) { - int noChunks; + // initialise chunk tree + tiledMap->chunkTree = NULL; - // 4 bytes for number of chunks - readb((char *)&noChunks, 4, tiledMap->file); size_t chunkSizeBytes = tiledMap->chunkWidth * tiledMap->chunkHeight; - for (int n = 0; n < noChunks; n++) { + // calculate how much space there is until the end of the file + // TODO save the number of chunks total to avoid having to jump around to find referenceso + // or just keep reading chunks until eof or other descriptor + long chunksStart = ftell(tiledMap->file); + fseek(tiledMap->file, 0, SEEK_END); + long totalChunksSize = ftell(tiledMap->file) - chunksStart; + + fseek(tiledMap->file, chunksStart, SEEK_SET); + + for (int n = 0; n < totalChunksSize; n += chunkSizeBytes + 8) { int x, y; readb((char *)&x, 4, tiledMap->file); readb((char *)&y, 4, tiledMap->file); long pointer = ftell(tiledMap->file); - // TODO casting to pointer here is maybe unsafe + kdtree_insert(&tiledMap->chunkTree, x, y, (char *) pointer); fseek(tiledMap->file, chunkSizeBytes, SEEK_CUR); } @@ -85,22 +109,40 @@ ChunkedTiledMap openTiledMap(char * filename) { tiledMap.atlasData = malloc(atlasSizeBytes); fread(tiledMap.atlasData, atlasSizeBytes, (size_t) 1, file); + tiledMap.tileCount = tiledMap.atlasSize[0]*tiledMap.atlasSize[1] + 1; + buildChunkTree(&tiledMap); return tiledMap; } +//! write a chunk to the file +char* writeChunk(ChunkedTiledMap *tiledMap, int x, int y, char * chunk) { + size_t chunkSizeBytes = tiledMap->chunkWidth * tiledMap->chunkHeight; + + + long pos = (long) kdtree_search(tiledMap->chunkTree, x, y); + + fseek(tiledMap->file, pos, SEEK_SET); + fwrite(chunk, 1, chunkSizeBytes, tiledMap->file); + return chunk; +} + char* loadChunk(ChunkedTiledMap tiledMap, int x, int y) { // TODO add caching for this size_t chunkSizeBytes = tiledMap.chunkWidth * tiledMap.chunkHeight; char * chunk = malloc(chunkSizeBytes); long pos = (long) kdtree_search(tiledMap.chunkTree, x, y); + // if this chunk is not indexed, return NULL + if (pos == 0) + return NULL; + fseek(tiledMap.file, pos, SEEK_SET); fread(chunk, 1, chunkSizeBytes, tiledMap.file); return chunk; } -void appendChunk(ChunkedTiledMap *tiledMap, int x, int y, char * chunk) { +char * appendChunk(ChunkedTiledMap *tiledMap, int x, int y, char * chunk) { // TODO does this actually need tiledMap as a pointer size_t chunkSizeBytes = tiledMap->chunkWidth * tiledMap->chunkHeight; @@ -108,11 +150,51 @@ void appendChunk(ChunkedTiledMap *tiledMap, int x, int y, char * chunk) { // calculate position before writing long pos = ftell(tiledMap->file) + 8; - kdtree_insert(&tiledMap->chunkTree, x, y, chunk); + kdtree_insert(&tiledMap->chunkTree, x, y, (char *)pos); + int chunkx, chunky; writeb((char *) &x, 4, tiledMap->file); writeb((char *) &y, 4, tiledMap->file); fwrite(chunk, 1, chunkSizeBytes, tiledMap->file); + + return chunk; +} + +char * appendEmptyChunk(ChunkedTiledMap * tiledMap, int x, int y) { + char * chunk = calloc(tiledMap->chunkWidth*tiledMap->chunkHeight, 1); + return appendChunk(tiledMap, x, y, chunk); +} + +char getChunkedTile(ChunkedTiledMap tiledMap, int x, int y) { + // TODO put this calculation in function + int inChunkX = x % tiledMap.chunkWidth; + int inChunkY = y % tiledMap.chunkHeight; + int chunkX = (x - inChunkX) / tiledMap.chunkWidth; + int chunkY = (y - inChunkY) / tiledMap.chunkHeight; + + char * chunk = loadChunk(tiledMap, chunkX, chunkY); + if (chunk == NULL) + return 0; + + char v = chunk[inChunkY * tiledMap.chunkWidth + inChunkX]; + return v; +} + +char setChunkedTile(ChunkedTiledMap * tiledMap, int x, int y, char value) { + int inChunkX = x % tiledMap->chunkWidth; + int inChunkY = y % tiledMap->chunkHeight; + int chunkX = (x - inChunkX) / tiledMap->chunkWidth; + int chunkY = (y - inChunkY) / tiledMap->chunkHeight; + + char * chunk = loadChunk(*tiledMap, chunkX, chunkY); + if (chunk == NULL) + chunk = appendEmptyChunk(tiledMap, chunkX, chunkY); + + chunk[inChunkY * tiledMap->chunkWidth + inChunkX] = value; + + writeChunk(tiledMap, chunkX, chunkY, chunk); + + return value; } @@ -136,7 +218,7 @@ void writeTiledMapHeader(ChunkedTiledMap tiledMap) { // TODO when caching, commit everything left in cache here } -ChunkedTiledMap newTiledMap(char * filename, Image atlas, int tileSize, int chunkWidth, int chunkHeight, int width, int height) { +ChunkedTiledMap openNewTiledMap(char * filename, Image atlas, int tileSize, int chunkWidth, int chunkHeight, int width, int height) { ChunkedTiledMap tiledMap; tiledMap.chunkWidth = chunkWidth; tiledMap.chunkHeight = chunkHeight; @@ -147,8 +229,11 @@ ChunkedTiledMap newTiledMap(char * filename, Image atlas, int tileSize, int chun tiledMap.atlasSize[1] = atlas.height / tileSize; tiledMap.atlasData = LoadImageColors(atlas); + tiledMap.tileCount = tiledMap.atlasSize[0]*tiledMap.atlasSize[1] + 1; - if (!(tiledMap.file = fopen(filename, "r+b"))) { + tiledMap.chunkTree = NULL; + + if (!(tiledMap.file = fopen(filename, "wb"))) { fprintf(stderr, "Failed to load %s\n", filename); } @@ -159,6 +244,13 @@ ChunkedTiledMap newTiledMap(char * filename, Image atlas, int tileSize, int chun appendChunk(&tiledMap, x, y, chunk); } } + + // reopen the file in read+write mode + fclose(tiledMap.file); + + if (!(tiledMap.file = fopen(filename, "r+b"))) { + fprintf(stderr, "Failed to load %s\n", filename); + } return tiledMap; } @@ -169,5 +261,3 @@ void closeTiledMap(ChunkedTiledMap tiledMap) { fclose(tiledMap.file); } - - diff --git a/src/chunkedtiledmap.h b/src/chunkedtiledmap.h index 0d5c5d0..8bc2aaa 100644 --- a/src/chunkedtiledmap.h +++ b/src/chunkedtiledmap.h @@ -1,9 +1,6 @@ #include #include "kdtree.h" -const int i = 1; -#define is_bigendian() ( (*(char*)&i) == 0 ) - typedef struct ChunkedTiledMap { FILE * file; int chunkWidth; @@ -14,3 +11,14 @@ typedef struct ChunkedTiledMap { Color * atlasData; kdtree_t * chunkTree; } ChunkedTiledMap; + +void textureFromPixels(Texture2D *texOut, Color *pixels, int width, int height); +ChunkedTiledMap openTiledMap(char * filename); +char * loadChunk(ChunkedTiledMap tiledMap, int x, int y); +char getChunkedTile(ChunkedTiledMap tiledMap, int x, int y); +char setChunkedTile(ChunkedTiledMap * tiledMap, int x, int y, char value); +char * appendChunk(ChunkedTiledMap * tiledMap, int x, int y, char * chunk); +void writeTiledMapHeader(ChunkedTiledMap tiledMap); +ChunkedTiledMap openNewTiledMap(char * filename, Image atlas, int tileSize, int chunkWidth, int chunkHeight, int width, int height); +void closeTiledMap(ChunkedTiledMap tiledMap); + diff --git a/src/editor.c b/src/editor.c index eddd6ad..46afe37 100644 --- a/src/editor.c +++ b/src/editor.c @@ -22,7 +22,7 @@ void drawOverlay(Tiled tiled) { } void modifyTile(Tiled *tiled, int tile) { - setTiledMapTile(tiled->tiledMap, selectedTile, tile); + setChunkedTile(&tiled->tiledMap, selectedTile[0], selectedTile[1], tile); redrawTiledMap(*tiled); } @@ -34,10 +34,10 @@ void setDrawMode(Tiled *tiled, int tile) { void handleInputs(Tiled *tiled) { if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) - setDrawMode(tiled, getTiledMapTile(tiled->tiledMap, selectedTile) + 1); + setDrawMode(tiled, getChunkedTile(tiled->tiledMap, selectedTile[0], selectedTile[1]) + 1); if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) - setDrawMode(tiled, getTiledMapTile(tiled->tiledMap, selectedTile) - 1); + setDrawMode(tiled, getChunkedTile(tiled->tiledMap, selectedTile[0], selectedTile[1]) - 1); if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE)) setDrawMode(tiled, 0); @@ -59,8 +59,8 @@ void update(Tiled *tiled) { updateTiledCamera(tiled); Vector2 mousePos = GetMousePosition(); Vector2 mapPos = translateTiledPosition(*tiled, mousePos); - if (mapPos.x >= 0 && mapPos.x < tiled->tiledMap.width - && mapPos.y >= 0 && mapPos.y < tiled->tiledMap.height) { + if (mapPos.x >= 0 && mapPos.x < tiled->mapSize[0] + && mapPos.y >= 0 && mapPos.y < tiled->mapSize[1]) { lastSelectedTile[0] = selectedTile[0]; lastSelectedTile[1] = selectedTile[1]; selectedTile[0] = mapPos.x; @@ -69,7 +69,7 @@ void update(Tiled *tiled) { handleInputs(tiled); } -TiledMap launchEditor(TiledMap tiledMap) { +ChunkedTiledMap launchEditor(ChunkedTiledMap tiledMap) { SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(SCREEN_W, SCREEN_H, "tiled"); @@ -92,7 +92,7 @@ TiledMap launchEditor(TiledMap tiledMap) { unloadTiled(&tiled); CloseWindow(); - return tiled.tiledMap; + return tiledMap; } void printUsage(char *progname) { @@ -104,11 +104,14 @@ int main(int argc, char *argv[]) { char * tiledFilePath; const char * atlasFilePath = NULL; int tileSize = 16; - int mapSize = 16; + int mapSize = 2; + int chunkSize = 2; int flags, opt; - while ((opt = getopt(argc, argv, "s:a:h")) != -1) { + while ((opt = getopt(argc, argv, "c:s:a:h")) != -1) { switch (opt) { + case 'c': + chunkSize = atoi(optarg); case 's': mapSize = atoi(optarg); case 't': @@ -123,7 +126,7 @@ int main(int argc, char *argv[]) { tiledFilePath = argv[optind]; - TiledMap tiledMap; + ChunkedTiledMap tiledMap; if (access(tiledFilePath, F_OK)) { if (atlasFilePath == NULL) { fprintf(stderr, "Atlas file must be specified!\n"); @@ -131,11 +134,11 @@ int main(int argc, char *argv[]) { } Image atlasImage = LoadImage(atlasFilePath); - tiledMap = newTiledMap(atlasImage, tileSize, mapSize, mapSize); + tiledMap = openNewTiledMap(tiledFilePath, atlasImage, tileSize, chunkSize, chunkSize, mapSize, mapSize); } else { - tiledMap = loadTiledMap(tiledFilePath); + tiledMap = openTiledMap(tiledFilePath); } - TiledMap editedTiledMap = launchEditor(tiledMap); - saveTiledMap(tiledFilePath, tiledMap); + launchEditor(tiledMap); + closeTiledMap(tiledMap); } diff --git a/src/kdtree.c b/src/kdtree.c index ab5aa98..551bc5c 100644 --- a/src/kdtree.c +++ b/src/kdtree.c @@ -1,5 +1,9 @@ #include "kdtree.h" +void print_node(kdtree_t *tree) { + printf("[%d,%d] %ld\n", tree->x, tree->y, (long)tree->value); +} + kdtree_t * kdtree_create(int x, int y, char * value) { kdtree_t * tree = malloc(sizeof(kdtree_t)); tree->x = x; diff --git a/src/kdtree.h b/src/kdtree.h index e121442..a5c178e 100644 --- a/src/kdtree.h +++ b/src/kdtree.h @@ -31,3 +31,6 @@ int kdtree_fwrite(kdtree_t *root, FILE *file); //! read a tree from file int kdtree_fread(kdtree_t **root, FILE *file); +//! print a single node (debug purposes) +void print_node(kdtree_t *tree); + diff --git a/src/tiled.c b/src/tiled.c index 43afa7b..f490d6a 100644 --- a/src/tiled.c +++ b/src/tiled.c @@ -3,6 +3,8 @@ #include "tiled.h" +int alpha =0; + void updateCamera(Vector2 *offset, float *zoom) { if (IsKeyDown(KEY_UP)) offset->y += 16.0f / *zoom; if (IsKeyDown(KEY_DOWN)) offset->y -= 16.0f/ *zoom; @@ -15,6 +17,7 @@ void updateCamera(Vector2 *offset, float *zoom) { void updateTiledCamera(Tiled *tiled) { updateCamera(&tiled->offset, &tiled->zoom); + alpha++; } @@ -47,12 +50,11 @@ Vector2 translateTiledScreenPosition(Tiled tiled, Vector2 tiledPos) { void redrawTiledMap(Tiled tiled) { BeginTextureMode(tiled.tilemapTexture); - for (int y = 0; y < tiled.tiledMap.height; y++) { - for (int x = 0; x < tiled.tiledMap.width; x++) { - int i = (tiled.tiledMap.height - y - 1)*tiled.tiledMap.width + x; + for (int y = 0; y < tiled.mapSize[1]; y++) { + for (int x = 0; x < tiled.mapSize[0]; x++) { + unsigned char v = getChunkedTile(tiled.tiledMap, x, tiled.mapSize[1] - y - 1); Color c = (Color){ - tiled.tiledMap.tilelayout[i], - 0, 0, 255 + v, 0, 0, 255 }; DrawPixel(x, y, c); } @@ -62,17 +64,18 @@ void redrawTiledMap(Tiled tiled) { } -Tiled initTiled(TiledMap tiledMap) { +Tiled initTiled(ChunkedTiledMap tiledMap) { Tiled tiled; tiled.tiledMap = tiledMap; tiled.offset = (Vector2) {0, 0}; tiled.zoom = 64; - tiled.mapSize[0] = tiledMap.width; - tiled.mapSize[1] = tiledMap.height; + // TODO mapSize is obsolete, should be visible map size + tiled.mapSize[0] = tiledMap.chunkWidth * 20; + tiled.mapSize[1] = tiledMap.chunkHeight * 20; tiled.targetTexture = LoadRenderTexture(1, 1); - tiled.tilemapTexture = LoadRenderTexture(tiledMap.width, tiledMap.width); + tiled.tilemapTexture = LoadRenderTexture(tiled.mapSize[0], tiled.mapSize[1]); tiled.atlasSize[0] = tiledMap.atlasSize[0]; tiled.atlasSize[1] = tiledMap.atlasSize[1]; @@ -120,29 +123,3 @@ void drawTiled(Tiled *tiled) { //(Vector2){0, 0}, //WHITE); } - -int launchTiledView() { - SetConfigFlags(FLAG_WINDOW_RESIZABLE); - InitWindow(SCREEN_W, SCREEN_H, "tiled"); - - TiledMap tiledMap = loadTiledMap("map.tiles"); - Tiled tiled = initTiled(tiledMap); - - while (!WindowShouldClose()) { - updateTiledCamera(&tiled); - - BeginDrawing(); - - ClearBackground(LIGHTGRAY); - - drawTiled(&tiled); - DrawFPS(16, 16); - - EndDrawing(); - } - - unloadTiled(&tiled); - - CloseWindow(); - return 0; -} diff --git a/src/tiled.h b/src/tiled.h index 9890a72..11518e7 100644 --- a/src/tiled.h +++ b/src/tiled.h @@ -1,12 +1,12 @@ #include -#include "tiledmap.h" +#include "chunkedtiledmap.h" #define SCREEN_W 1280 #define SCREEN_H 720 typedef struct Tiled { - TiledMap tiledMap; + ChunkedTiledMap tiledMap; float zoom; Vector2 offset; @@ -33,7 +33,7 @@ typedef struct Tiled { void updateTiledCamera(Tiled *tiled); Vector2 translateTiledPosition(Tiled tiled, Vector2 screenPos); Vector2 translateTiledScreenPosition(Tiled tiled, Vector2 tiledPos); -Tiled initTiled(TiledMap tiledMap); +Tiled initTiled(ChunkedTiledMap tiledMap); void drawTiled(Tiled *tiled); void unloadTiled(Tiled *tiled); void redrawTiledMap(Tiled tiled); diff --git a/src/tiledmap.c b/src/tiledmap.c index 69dcdaa..e274a6e 100644 --- a/src/tiledmap.c +++ b/src/tiledmap.c @@ -111,7 +111,7 @@ TiledMap loadTiledMap(char * filename) { return tiledMap; } -TiledMap newTiledMap(Image atlas, int tileSize, int width, int height) { +TiledMap openNewTiledMap(Image atlas, int tileSize, int width, int height) { TiledMap tiledMap; tiledMap.width = width; tiledMap.height = height; -- cgit v1.2.1