From ca1cd4b1f902a4e4c0112a5fd8442dc5ee3c96a4 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Wed, 8 Nov 2023 08:37:09 +0100 Subject: [PATCH] Proper layer rendering --- engine/CMakeLists.txt | 2 - engine/breeze.h | 1 - engine/breeze/world/layer.c | 1 - engine/breeze/world/layer.h | 4 - engine/breeze/world/map.c | 143 ++++++++++++++++++++++++++++++++++ engine/breeze/world/map.h | 58 ++++++++++++++ engine/breeze/world/tileset.h | 16 ++-- game/main.c | 82 ++----------------- 8 files changed, 218 insertions(+), 89 deletions(-) delete mode 100644 engine/breeze/world/layer.c delete mode 100644 engine/breeze/world/layer.h diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 858e36a..2c38aca 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -24,7 +24,6 @@ set(BreezeSources breeze/utils/tokenizer.c - breeze/world/layer.c breeze/world/map.c breeze/world/tileset.c ) @@ -37,7 +36,6 @@ set(BreezeHeaders breeze/utils/tokenizer.h - breeze/world/layer.h breeze/world/map.h breeze/world/tileset.h diff --git a/engine/breeze.h b/engine/breeze.h index 37ff92f..541f45b 100644 --- a/engine/breeze.h +++ b/engine/breeze.h @@ -8,7 +8,6 @@ #include "breeze/utils/tokenizer.h" -#include "breeze/world/layer.h" #include "breeze/world/map.h" #include "breeze/world/tileset.h" diff --git a/engine/breeze/world/layer.c b/engine/breeze/world/layer.c deleted file mode 100644 index facf38b..0000000 --- a/engine/breeze/world/layer.c +++ /dev/null @@ -1 +0,0 @@ -#include "layer.h" diff --git a/engine/breeze/world/layer.h b/engine/breeze/world/layer.h deleted file mode 100644 index 6fa5ee3..0000000 --- a/engine/breeze/world/layer.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef BREEZE_LAYER_H -#define BREEZE_LAYER_H - -#endif //BREEZE_LAYER_H diff --git a/engine/breeze/world/map.c b/engine/breeze/world/map.c index b323fbb..290c0f0 100644 --- a/engine/breeze/world/map.c +++ b/engine/breeze/world/map.c @@ -1 +1,144 @@ #include "map.h" + +#include "../core/memory.h" +#include "../math/vec2i.h" + +#include + +BzTileMap BZ_TILEMAP_INVALID = {.isValid = false}; + +BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { + BzTileMap map = {}; + i32 tilesetCount = desc->tilesetCount; + if (tilesetCount == 0) { + // Auto detect tileset count. + for (i32 i = 0; i < BZ_MAX_MAP_TILESETS; i++) { + if (!desc->tilesets[i].isValid) + break; + tilesetCount++; + } + } + map.tilesetCount = tilesetCount; + for (i32 i = 0; i < map.tilesetCount; i++) { + map.tilesets[i] = desc->tilesets[i]; + } + + cute_tiled_map_t *cuteMap = cute_tiled_load_map_from_file(desc->path, NULL); + + map.backgroundColor = GetColor(cuteMap->backgroundcolor); + + map.width = cuteMap->width; + map.height = cuteMap->height; + map.tileWidth = cuteMap->tilewidth; + map.tileHeight = cuteMap->tileheight; + + cute_tiled_layer_t *cuteLayer = cuteMap->layers; + while (cuteLayer) { + BZ_ASSERT(map.layerCount < BZ_MAX_MAP_LAYERS); + + BzTileLayer *layer = map.layers + map.layerCount; + layer->id = cuteLayer->id; + + layer->dataCount = cuteLayer->data_count; + layer->data = NULL; + if (layer->dataCount > 0) { + layer->data = bzAlloc(layer->dataCount * sizeof(*layer->data)); + layer->minData = layer->maxData = (i16) cuteLayer->data[0]; + for (i32 i = 0; i < layer->dataCount; i++) { + layer->data[i] = (i16) cuteLayer->data[i]; + if (layer->data[i] < layer->minData) + layer->minData = layer->data[i]; + else if (layer->data[i] > layer->maxData) + layer->maxData = layer->data[i]; + } + } + + layer->width = cuteLayer->width; + layer->height = cuteLayer->height; + + layer->offsetX = cuteLayer->offsetx; + layer->offsetY = cuteLayer->offsety; + layer->opacity = cuteLayer->opacity; + + map.layerCount++; + cuteLayer = cuteLayer->next; + } + + cute_tiled_tileset_t *cuteTileset = cuteMap->tilesets; + tilesetCount = 0; + while ((cuteTileset = cuteTileset->next)) tilesetCount++; + BZ_ASSERT(tilesetCount == map.tilesetCount); + + cuteTileset = cuteMap->tilesets; + for (i32 i = 0; i < map.tilesetCount; i++) { + BzTileset *tileset = map.tilesets + i; + tileset->startID = cuteTileset->firstgid; + cuteTileset = cuteTileset->next; + } + + // Assign tilesets to layers + for (i32 i = 0; i < map.layerCount; i++) { + BzTileLayer *layer = map.layers + i; + layer->tilesetIdx = -1; + for (i32 j = map.tilesetCount - 1; j >= 0; j--) { + BzTileset *tileset = map.tilesets + j; + + if (tileset->startID >= layer->minData && + tileset->startID <= layer->maxData) { + layer->tilesetIdx = j; + break; + } + } + } + + cute_tiled_free_map(cuteMap); + + map.isValid = true; + return map; +} + +static void drawLayer(BzTileLayer *layer, BzTileset *tileset) { + if (!tileset) return; + if (layer->minData == layer->maxData) return; + Vector2 drawPos = {layer->offsetX, layer->offsetY}; + + for (i32 y = 0; y < layer->height; y++) { + for (i32 x = 0; x < layer->width; x++) { + i16 tile = bzTileLayerGetTile(layer, x, y); + if (tile - tileset->startID != -1) { + Rectangle rec = bzTilesetGetTileRegion(tileset, tile); + DrawTextureRec(tileset->tiles, rec, drawPos, WHITE); + } + drawPos.x += (float) tileset->tileWidth; + } + drawPos.x = layer->offsetX; + drawPos.y += (float) tileset->tileHeight; + } + +} + +void bzTileMapDraw(BzTileMap *map) { + for (i32 i = 0; i < map->layerCount; i++) { + BzTileLayer *layer = map->layers + i; + BzTileset *tileset = NULL; + if (layer->tilesetIdx != -1) { + tileset = map->tilesets + layer->tilesetIdx; + } + drawLayer(map->layers + i, tileset); + } +} + +void bzTileMapDestroy(BzTileMap *tilemap) { + for (i32 i = 0; i < tilemap->layerCount; i++) { + BzTileLayer *layer = tilemap->layers + i; + bzFree(layer->data); + layer->data = NULL; + layer->dataCount = 0; + } + *tilemap = BZ_TILEMAP_INVALID; +} + + +int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) { + return layer->data[layer->width * y + x]; +} diff --git a/engine/breeze/world/map.h b/engine/breeze/world/map.h index e235a51..105d436 100644 --- a/engine/breeze/world/map.h +++ b/engine/breeze/world/map.h @@ -1,4 +1,62 @@ #ifndef BREEZE_MAP_H #define BREEZE_MAP_H +#include "tileset.h" + +#define BZ_MAX_MAP_LAYERS 16 +#define BZ_MAX_MAP_TILESETS 8 + + +typedef struct BzTileLayer { + i32 id; + + int16_t *data; + i32 dataCount; + i16 minData; + i16 maxData; + + i32 width; + i32 height; + + f32 offsetX; + f32 offsetY; + f32 opacity; + + i32 tilesetIdx; +} BzTileLayer; + + +typedef struct BzTileMapDesc { + const char *path; + BzTileset tilesets[BZ_MAX_MAP_TILESETS]; + i32 tilesetCount; +} BzTileMapDesc; + +typedef struct BzTileMap { + Color backgroundColor; + + i32 width; + i32 height; + i32 tileWidth; + i32 tileHeight; + + BzTileLayer layers[BZ_MAX_MAP_LAYERS]; + i32 layerCount; + + BzTileset tilesets[BZ_MAX_MAP_TILESETS]; + i32 tilesetCount; + + bool isValid; +} BzTileMap; + +extern BzTileMap BZ_TILEMAP_INVALID; + +int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y); + +BzTileMap bzTileMapCreate(const BzTileMapDesc *desc); +void bzTileMapDraw(BzTileMap *map); +void bzTileMapDestroy(BzTileMap *tilemap); + + + #endif //BREEZE_MAP_H diff --git a/engine/breeze/world/tileset.h b/engine/breeze/world/tileset.h index aa03721..78eecee 100644 --- a/engine/breeze/world/tileset.h +++ b/engine/breeze/world/tileset.h @@ -1,6 +1,8 @@ #ifndef BREEZE_TILESET_H #define BREEZE_TILESET_H +#include "../defines.h" + #include typedef struct BzTilesetDesc { @@ -10,13 +12,13 @@ typedef struct BzTilesetDesc { typedef struct BzTileset { Texture2D tiles; - int startID; - int tileWidth; - int tileHeight; - int width; - int height; - int offsetX; - int offsetY; + i32 startID; + i32 tileWidth; + i32 tileHeight; + i32 width; + i32 height; + i32 offsetX; + i32 offsetY; bool isValid; } BzTileset; diff --git a/game/main.c b/game/main.c index 6cfaa58..bee5c77 100644 --- a/game/main.c +++ b/game/main.c @@ -1,54 +1,21 @@ #include #include -#include #define BZ_ENTRYPOINT #include -static void drawTile(Texture2D texture, int tid, int tileSetWidth, int size, Vector2 pos) { - Rectangle rec = {(tid % tileSetWidth) * size, (tid / tileSetWidth) * size, size, size}; - - DrawTextureRec(texture, rec, pos, WHITE); -} - -static void drawLayer(cute_tiled_layer_t *layer, BzTileset *tileset) { - Vector2 pos = {layer->offsetx, layer->offsety}; - - for (int y = 0; y < layer->height; y++) { - for (int x = 0; x < layer->width; x++) { - int tile = layer->data[y * layer->width + x]; - if (tile - tileset->startID != -1) { - Rectangle rec = bzTilesetGetTileRegion(tileset, tile); - DrawTextureRec(tileset->tiles, rec, pos, WHITE); - } - pos.x += tileset->tileWidth; - } - pos.x = layer->offsetx; - pos.y += tileset->tileHeight; - } -} - typedef struct Game { - cute_tiled_map_t *map; Camera2D camera; BzTileset terrainTileset; BzTileset buildingsTileset; - cute_tiled_layer_t *terrain; - cute_tiled_layer_t *trees; - cute_tiled_layer_t *trees2; - cute_tiled_layer_t *buildings; + BzTileMap map; } Game; static Game GAME = {}; bool init(Game *game) { - game->map = cute_tiled_load_map_from_file("assets/maps/test.tmj", NULL); - cute_tiled_tileset_t *terrainSource = cute_tiled_load_external_tileset("assets/terrain.tsj", NULL); - - cute_tiled_tileset_t *buildingsSource = cute_tiled_load_external_tileset("assets/buildings.tsj", NULL); - game->terrainTileset = bzTilesetCreate( &(BzTilesetDesc) { .path="assets/terrain.tsj", .texturePath="assets/terrain.png" @@ -58,42 +25,12 @@ bool init(Game *game) { .texturePath="assets/buildings.png" }); + game->map = bzTileMapCreate(&(BzTileMapDesc) { + .path="assets/maps/test.tmj", + .tilesets[0]=game->terrainTileset, + .tilesets[1]=game->buildingsTileset + }); - cute_tiled_tileset_t *tileset = game->map->tilesets; - game->terrainTileset.startID = tileset->firstgid; - tileset = tileset->next; - game->buildingsTileset.startID = tileset->firstgid; - - cute_tiled_free_external_tileset(terrainSource); - cute_tiled_free_external_tileset(buildingsSource); - - - - game->terrain = NULL; - game->trees = NULL; - game->trees2 = NULL; - game->buildings = NULL; - // loop over the map's layers - cute_tiled_layer_t* layer = game->map->layers; - while (layer) - { - int* data = layer->data; - int data_count = layer->data_count; - - if (strcmp("Terrain", layer->name.ptr) == 0) { - game->terrain = layer; - } else if (strcmp("Foliage", layer->name.ptr) == 0) { - - } else if (strcmp("Trees", layer->name.ptr) == 0) { - game->trees = layer; - } else if (strcmp("TreesS", layer->name.ptr) == 0) { - game->trees2 = layer; - } else if (strcmp("Buildings", layer->name.ptr) == 0) { - game->buildings = layer; - } - - layer = layer->next; - } int screenWidth = 1280; int screenHeight = 720; @@ -108,7 +45,7 @@ bool init(Game *game) { void deinit(Game *game) { bzTilesetDestroy(&game->terrainTileset); bzTilesetDestroy(&game->buildingsTileset); - cute_tiled_free_map(game->map); + bzTileMapDestroy(&game->map); } void render(float dt, Game *game) { Camera2D *camera = &game->camera; @@ -126,10 +63,7 @@ void render(float dt, Game *game) { BeginMode2D(*camera); ClearBackground(RAYWHITE); - drawLayer(game->terrain, &game->terrainTileset); - drawLayer(game->trees, &game->terrainTileset); - drawLayer(game->trees2, &game->terrainTileset); - drawLayer(game->buildings, &game->buildingsTileset); + bzTileMapDraw(&game->map); EndMode2D(); EndDrawing();