Separate object layers, asign layers to proper slots

This commit is contained in:
2023-11-09 08:38:57 +01:00
parent 4458a26c4f
commit fa79af2a17
9 changed files with 226 additions and 72 deletions

View File

@@ -3,6 +3,8 @@ project(Breeze C)
set(CMAKE_C_STANDARD 11)
add_compile_definitions(DEBUG_MODE)
set(BUILD_EXAMPLES false)
add_subdirectory(libs/raylib-4.5.0)
@@ -38,6 +40,7 @@ set(BreezeHeaders
breeze/math/vec2i.h
breeze/utils/string.h
breeze/utils/tokenizer.h
breeze/world/map.h

View File

@@ -6,6 +6,7 @@
#include "breeze/math/vec2i.h"
#include "breeze/utils/string.h"
#include "breeze/utils/tokenizer.h"
#include "breeze/world/map.h"

View File

@@ -0,0 +1,20 @@
#ifndef BREEZE_STRING_H
#define BREEZE_STRING_H
#include "../defines.h"
typedef u32 BzStringHashFunc(const char *str);
// djb2 hash algorithm
// From: https://stackoverflow.com/questions/7666509/hash-function-for-string
// http://www.cse.yorku.ca/~oz/hash.html
static u32 bzStringDefaultHash(const char *str) {
u32 hash = 5381;
int c;
while ((c = (int) *str++)) {
hash = ((hash << 5) + hash) + c; /* hash + 33 + c */
}
return hash;
}
#endif //BREEZE_STRING_H

View File

@@ -4,6 +4,7 @@
#include "../math/vec2i.h"
#include <cute_tiled.h>
#include <string.h>
BzTileMap BZ_TILEMAP_INVALID = {.isValid = false};
@@ -12,18 +13,71 @@ int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) {
return layer->data[layer->width * y + x];
}
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++;
static void handleTileLayer(BzTileLayer *layer, cute_tiled_layer_t *cuteLayer) {
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];
}
}
map.tilesetCount = tilesetCount;
layer->width = cuteLayer->width;
layer->height = cuteLayer->height;
layer->offsetX = cuteLayer->offsetx;
layer->offsetY = cuteLayer->offsety;
layer->opacity = cuteLayer->opacity;
}
// tileset.c
BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object);
static void handleTileObjectLayer(BzTileObjectLayer *layer, cute_tiled_layer_t *cuteLayer,
BzStringHashFunc hashFunc) {
// Count objects
layer->objectCount = 0;
cute_tiled_object_t *object = cuteLayer->objects;
while (object) {
layer->objectCount++;
object = object->next;
}
layer->objects = bzAlloc(layer->objectCount * sizeof(*layer->objects));
object = cuteLayer->objects;
for (i32 i = 0; i < layer->objectCount; i++) {
layer->objects[i].id = hashFunc(object->name.ptr);
layer->objects[i].shape = bzCuteObjectToTileShape(object);
object = object->next;
}
}
static i32 findSlot(const char *name, const BzTileLayerDesc desc[BZ_MAX_MAP_LAYERS]) {
for (i32 i = 0; i < BZ_MAX_MAP_LAYERS; i++) {
if (!desc[i].name) break;
if (strcmp(name, desc[i].name) == 0) return i;
}
return -1;
}
BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
BzTileMap map = {};
// Auto detect tileset count.
for (i32 i = 0; i < BZ_MAX_MAP_TILESETS; i++) {
if (!desc->tilesets[i].isValid)
break;
map.tilesetCount++;
}
for (i32 i = 0; i < map.tilesetCount; i++) {
map.tilesets[i] = desc->tilesets[i];
}
@@ -40,38 +94,49 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
cute_tiled_layer_t *cuteLayer = cuteMap->layers;
while (cuteLayer) {
BZ_ASSERT(map.layerCount < BZ_MAX_MAP_LAYERS);
BZ_ASSERT(map.objectLayerCount < 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];
// Find slot
i32 slot = -1;
for (i32 i = 0; i < BZ_MAX_MAP_LAYERS; i++) {
const BzTileLayerDesc *layerDesc = desc->layers + i;
const BzTileObjectsDesc *objectsDesc = desc->objectLayers + i;
if (layerDesc->name && strcmp(layerDesc->name, cuteLayer->name.ptr) == 0 ||
objectsDesc->name && strcmp(objectsDesc->name, cuteLayer->name.ptr) == 0) {
slot = i;
break;
} else if (!layerDesc->name && !objectsDesc->name) {
break;
}
}
if (slot == -1) {
cuteLayer = cuteLayer->next;
continue;
}
layer->width = cuteLayer->width;
layer->height = cuteLayer->height;
if (cuteLayer->data) {
BzTileLayer *layer = map.layers + slot;
const BzTileLayerDesc *layerDesc = desc->layers + slot;
handleTileLayer(layer, cuteLayer);
if (layerDesc->handler) layerDesc->handler(layer);
map.layerCount++;
} else {
BzTileObjectLayer *objectLayer = map.objectLayers + slot;
const BzTileObjectsDesc *objectLayerDesc = desc->objectLayers + slot;
BzStringHashFunc *hashFunc = objectLayerDesc->hashFunc;
if (!hashFunc)
hashFunc = bzStringDefaultHash;
handleTileObjectLayer(objectLayer, cuteLayer, hashFunc);
if (objectLayerDesc->handler) objectLayerDesc->handler(objectLayer);
map.objectLayerCount++;
}
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++;
int tilesetCount = 0;
for (; cuteTileset; cuteTileset = cuteTileset->next) tilesetCount++;
BZ_ASSERT(tilesetCount == map.tilesetCount);
cuteTileset = cuteMap->tilesets;
@@ -155,8 +220,8 @@ bool bzTileMapCanPlace(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 size
BzTileset *tileset = map->tilesets + layer->tilesetIdx;
i16 tile = bzTileLayerGetTile(layer, x, y);
BzTileCollider collider = bzTilesetGetTileCollider(tileset, tile);
if (collider.type != BZ_TILE_COLLIDER_NONE)
BzTileShape collider = bzTilesetGetTileCollider(tileset, tile);
if (collider.type != BZ_TILE_SHAPE_NONE)
return false;
}
}

View File

@@ -2,8 +2,9 @@
#define BREEZE_MAP_H
#include "tileset.h"
#include "../utils/string.h"
#define BZ_MAX_MAP_LAYERS 16
#define BZ_MAX_MAP_LAYERS 8
#define BZ_MAX_MAP_TILESETS 8
@@ -25,11 +26,36 @@ typedef struct BzTileLayer {
i32 tilesetIdx;
} BzTileLayer;
typedef struct BzTileObject {
u32 id;
BzTileShape shape;
} BzTileObject;
typedef struct BzTileObjectLayer {
BzTileObject *objects;
i32 objectCount;
} BzTileObjectLayer;
// Return true, if it should be added to map
typedef bool BzTileLayerHandler(BzTileLayer *layer);
typedef bool BzTileObjectsHandler(BzTileObjectLayer *objectLayer);
typedef struct BzTileLayerDesc {
const char *name; // Matches map layer names
BzTileLayerHandler *handler;
} BzTileLayerDesc;
typedef struct BzTileObjectsDesc {
const char *name; // Matches map layer names
BzTileObjectsHandler *handler;
BzStringHashFunc *hashFunc;
} BzTileObjectsDesc;
typedef struct BzTileMapDesc {
const char *path;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
i32 tilesetCount;
BzTileLayerDesc layers[BZ_MAX_MAP_LAYERS];
BzTileObjectsDesc objectLayers[BZ_MAX_MAP_LAYERS];
} BzTileMapDesc;
typedef struct BzTileMap {
@@ -43,6 +69,9 @@ typedef struct BzTileMap {
BzTileLayer layers[BZ_MAX_MAP_LAYERS];
i32 layerCount;
BzTileObjectLayer objectLayers[BZ_MAX_MAP_LAYERS];
i32 objectLayerCount;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
i32 tilesetCount;

View File

@@ -6,6 +6,25 @@
BzTileset BZ_TILESET_INVALID = {.isValid = false};
BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object) {
BzTileShape shape = {BZ_TILE_SHAPE_NONE};
if (object->ellipse)
shape.type = BZ_TILE_SHAPE_ELLIPSE;
else if (object->point)
shape.type = BZ_TILE_SHAPE_POINT;
else if (!object->vertices)
shape.type = BZ_TILE_SHAPE_RECT;
else
return shape;
shape.x = object->x;
shape.y = object->y;
shape.sizeX = object->width;
shape.sizeY = object->height;
return shape;
}
BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
BzTileset tileset = {};
cute_tiled_tileset_t *cuteTileset = cute_tiled_load_external_tileset(desc->path, NULL);
@@ -24,7 +43,7 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
tileset.tileCount = tileset.width * tileset.tileHeight;
tileset.tileColliders = bzAlloc(tileset.tileCount * sizeof(*tileset.tileColliders));
for (i32 i = 0; i < tileset.tileCount; i++) {
tileset.tileColliders[i] = (BzTileCollider) {BZ_TILE_COLLIDER_NONE};
tileset.tileColliders[i] = (BzTileShape) {BZ_TILE_SHAPE_NONE};
}
cute_tiled_tile_descriptor_t *cuteTile = cuteTileset->tiles;
@@ -34,14 +53,7 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
// NOTE: Only supporting single collider (integer values)
if (cuteObject) {
BzTileCollider collider = {BZ_TILE_COLLIDER_RECT};
if (cuteObject->ellipse)
collider.type = BZ_TILE_COLLIDER_ELLIPSE;
collider.x = (i8) cuteObject->x;
collider.y = (i8) cuteObject->y;
collider.sizeX = (i8) cuteObject->width;
collider.sizeY = (i8) cuteObject->height;
BzTileShape collider = bzCuteObjectToTileShape(cuteObject);
tileset.tileColliders[cuteTile->tile_index] = collider;
}
}
@@ -68,11 +80,11 @@ Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) {
return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight,
tileset->tileWidth, tileset->tileHeight};
}
BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID) {
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID) {
tileID = tileID - tileset->startID;
if (tileID < 0 || tileID >= tileset->tileCount) {
return (BzTileCollider) {.type = BZ_TILE_COLLIDER_NONE};
return (BzTileShape) {.type = BZ_TILE_SHAPE_NONE};
}
return tileset->tileColliders[tileID];

View File

@@ -10,24 +10,26 @@ typedef struct BzTilesetDesc {
const char *texturePath;
} BzTilesetDesc;
typedef enum BzTileColliderType {
BZ_TILE_COLLIDER_NONE,
BZ_TILE_COLLIDER_RECT,
BZ_TILE_COLLIDER_ELLIPSE
} BzTileColliderType;
typedef enum BzTileShapeType {
BZ_TILE_SHAPE_NONE,
BZ_TILE_SHAPE_POINT,
BZ_TILE_SHAPE_RECT,
BZ_TILE_SHAPE_ELLIPSE,
//BZ_TILE_SHAPE_POLYGON
} BzTileShapeType;
typedef struct BzTileCollider {
BzTileColliderType type;
u8 x;
u8 y;
u8 sizeX;
u8 sizeY;
} BzTileCollider;
typedef struct BzTileShape {
BzTileShapeType type;
f32 x;
f32 y;
f32 sizeX;
f32 sizeY;
} BzTileShape;
typedef struct BzTileset {
Texture2D tiles;
i32 tileCount;
BzTileCollider *tileColliders;
BzTileShape *tileColliders;
i32 startID;
i32 tileWidth;
i32 tileHeight;
@@ -43,7 +45,7 @@ extern BzTileset BZ_TILESET_INVALID;
BzTileset bzTilesetCreate(const BzTilesetDesc *desc);
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID);
BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID);
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID);
void bzTilesetDestroy(BzTileset *tileset);