Rename world directory to map

This commit is contained in:
2023-11-09 12:22:56 +01:00
parent 8edcf9305c
commit dd96b23d32
7 changed files with 18 additions and 8 deletions

333
engine/breeze/map/map.c Normal file
View File

@@ -0,0 +1,333 @@
#include "map.h"
#include "../core/memory.h"
#include "../math/vec2i.h"
#include <cute_tiled.h>
#include <string.h>
BzTileMap BZ_TILEMAP_INVALID = {.isValid = false};
int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) {
return layer->data[layer->width * y + x];
}
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];
}
}
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 void createColliders(BzTileMap *map) {
map->collidersCount = map->width * map->height;
map->colliderMap = bzAlloc(map->collidersCount * sizeof(*map->colliderMap));
for (i32 i = 0; i < map->collidersCount; i++) {
map->colliderMap[i] = (BzTileCollider) {{BZ_TILE_SHAPE_NONE}};
}
// Top-most layer takes priority
for (i32 i = map->layerCount - 1; i >= 0; i--) {
BzTileLayer *layer = map->layers + i;
if (!layer->data) continue;
if (layer->tilesetIdx == -1) continue;
BzTileset *tileset = map->tilesets + layer->tilesetIdx;
for (i32 y = 0; y < map->height; y++) {
for (i32 x = 0; x < map->width; x++) {
i32 tile = bzTileLayerGetTile(layer, x, y);
BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tile);
if (tilesetShape.type == BZ_TILE_SHAPE_NONE ||
tilesetShape.type == BZ_TILE_SHAPE_POINT)
continue;
tilesetShape.x += layer->offsetX;
tilesetShape.y += layer->offsetY;
i32 colliderIdx = y * map->width + x;
BzTileCollider *collider = map->colliderMap + colliderIdx;
for (i32 sIdx = 0; sIdx < BZ_MAP_COLLIDER_DEPTH; sIdx++) {
BzTileShape *shape = collider->shapes + sIdx;
if (shape->type == BZ_TILE_SHAPE_NONE) {
*shape = tilesetShape;
break;
}
}
}
}
}
}
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];
}
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);
BZ_ASSERT(map.objectLayerCount < BZ_MAX_MAP_LAYERS);
// 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;
}
if (cuteLayer->data) {
BzTileLayer *layer = map.layers + slot;
const BzTileLayerDesc *layerDesc = desc->layers + slot;
handleTileLayer(layer, cuteLayer);
if (layerDesc->handler && !layerDesc->handler(layer)) {
bzFree(layer->data);
layer->data = NULL;
layer->dataCount = 0;
}
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)) {
bzFree(objectLayer->objects);
objectLayer->objects = NULL;
objectLayer->objectCount = 0;
}
map.objectLayerCount++;
}
cuteLayer = cuteLayer->next;
}
cute_tiled_tileset_t *cuteTileset = cuteMap->tilesets;
int tilesetCount = 0;
for (; cuteTileset; 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);
createColliders(&map);
map.isValid = true;
return map;
}
void bzTileMapDestroy(BzTileMap *tilemap) {
for (i32 i = 0; i < tilemap->layerCount; i++) {
BzTileLayer *layer = tilemap->layers + i;
if (layer->data) {
bzFree(layer->data);
layer->data = NULL;
layer->dataCount = 0;
}
}
for (i32 i = 0; i < tilemap->objectLayerCount; i++) {
BzTileObjectLayer *objectLayer = tilemap->objectLayers + i;
if (objectLayer->objects) {
bzFree(objectLayer->objects);
objectLayer->objects = NULL;
objectLayer->objectCount = 0;
}
}
bzFree(tilemap->colliderMap);
tilemap->collidersCount = 0;
*tilemap = BZ_TILEMAP_INVALID;
}
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;
}
}
static void drawObjectLayer(BzTileObjectLayer *objectLayer) {
Color color = ORANGE;
for (int i = 0; i < objectLayer->objectCount; i++) {
BzTileShape shape = objectLayer->objects[i].shape;
switch (shape.type) {
case BZ_TILE_SHAPE_NONE:
break;
case BZ_TILE_SHAPE_POINT:
DrawCircle(shape.x, shape.y, 2.0f, color);
break;
case BZ_TILE_SHAPE_RECT:
DrawRectangle(shape.x, shape.y, shape.sizeX, shape.sizeY, color);
break;
case BZ_TILE_SHAPE_ELLIPSE:
DrawEllipse(shape.x, shape.y, shape.sizeX, shape.sizeY, color);
break;
}
}
}
void bzTileMapDraw(BzTileMap *map) {
for (i32 i = 0; i < map->layerCount; i++) {
BzTileLayer *layer = map->layers + i;
if (!layer->data) continue;
BzTileset *tileset = NULL;
if (layer->tilesetIdx != -1) {
tileset = map->tilesets + layer->tilesetIdx;
}
drawLayer(map->layers + i, tileset);
}
for (i32 i = 0; i < map->objectLayerCount; i++) {
BzTileObjectLayer *objectLayer = map->objectLayers + i;
if (!objectLayer->objects) continue;
drawObjectLayer(objectLayer);
}
}
void bzTileMapDrawColliders(BzTileMap *map) {
Color color = RED;
color.a = 150;
for (i32 y = 0; y < map->height; y++) {
for (i32 x = 0; x < map->width; x++) {
i32 idx = y * map->width + x;
BzTileCollider collider = map->colliderMap[idx];
for (i32 i = 0; i < BZ_MAP_COLLIDER_DEPTH; i++) {
BzTileShape shape = collider.shapes[i];
if (shape.type == BZ_TILE_SHAPE_NONE)
break;
i32 posX = x * map->tileWidth + shape.x;
i32 posY = y * map->tileHeight + shape.y;
f32 sizeX = shape.sizeX;
f32 sizeY = shape.sizeY;
switch (shape.type) {
case BZ_TILE_SHAPE_NONE:
default:
break;
case BZ_TILE_SHAPE_RECT:
DrawRectangleLines(posX, posY, sizeX, sizeY, color);
break;
case BZ_TILE_SHAPE_ELLIPSE:
DrawEllipseLines(posX, posY, sizeX, sizeY, color);
break;
}
}
}
}
}
BzTileCollider bzTileMapGetCollider(BzTileMap *map, i32 x, i32 y) {
i32 idx = y * map->width + x;
if (idx < 0 || idx >= map->collidersCount) {
return (BzTileCollider) {{BZ_TILE_SHAPE_NONE}};
}
return map->colliderMap[idx];
}

111
engine/breeze/map/map.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef BREEZE_MAP_H
#define BREEZE_MAP_H
#include "tileset.h"
#include "../utils/string.h"
#define BZ_MAX_MAP_LAYERS 8
#define BZ_MAX_MAP_TILESETS 8
#define BZ_MAP_COLLIDER_DEPTH 2
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;
void *userData;
} BzTileLayer;
typedef struct BzTileObject {
u32 id;
BzTileShape shape;
void *userData;
} BzTileObject;
typedef struct BzTileObjectLayer {
BzTileObject *objects;
i32 objectCount;
} BzTileObjectLayer;
// Return true, if you want to keep data allocated
typedef bool BzTileLayerFunc(BzTileLayer *layer);
typedef bool BzTileObjectsFunc(BzTileObjectLayer *objectLayer);
typedef void BzTileLayerRenderFunc(BzTileLayer *layer);
typedef void BzTileObjectsRenderFunc(BzTileObjectLayer *objectLayer);
typedef struct BzTileLayerDesc {
const char *name; // Matches map layer names
BzTileLayerFunc *handler;
BzTileLayerRenderFunc *renderer;
} BzTileLayerDesc;
typedef struct BzTileObjectsDesc {
const char *name; // Matches map layer names
BzTileObjectsFunc *handler;
BzTileObjectsRenderFunc *renderer;
BzStringHashFunc *hashFunc;
} BzTileObjectsDesc;
typedef struct BzTileMapDesc {
const char *path;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
BzTileLayerDesc layers[BZ_MAX_MAP_LAYERS];
BzTileObjectsDesc objectLayers[BZ_MAX_MAP_LAYERS];
} BzTileMapDesc;
typedef struct BzTileCollider {
BzTileShape shapes[BZ_MAP_COLLIDER_DEPTH];
} BzTileCollider;
typedef struct BzTileMap {
Color backgroundColor;
i32 width;
i32 height;
i32 tileWidth;
i32 tileHeight;
BzTileCollider *colliderMap;
i32 collidersCount;
BzTileLayer layers[BZ_MAX_MAP_LAYERS];
i32 layerCount;
BzTileObjectLayer objectLayers[BZ_MAX_MAP_LAYERS];
i32 objectLayerCount;
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 bzTileMapDestroy(BzTileMap *tilemap);
void bzTileMapDraw(BzTileMap *map);
void bzTileMapDrawColliders(BzTileMap *map);
BzTileCollider bzTileMapGetCollider(BzTileMap *map, i32 x, i32 y);
#endif //BREEZE_MAP_H

105
engine/breeze/map/tileset.c Normal file
View File

@@ -0,0 +1,105 @@
#include <cute_tiled.h>
#include <stdio.h>
#include "tileset.h"
#include "../core/memory.h"
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;
if (shape.type == BZ_TILE_SHAPE_ELLIPSE) {
// Adjust to use radius and position to be center
shape.sizeX *= 0.5f;
shape.sizeY *= 0.5f;
shape.x += shape.sizeX;
shape.y += shape.sizeY;
}
return shape;
}
BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
BzTileset tileset = {};
cute_tiled_tileset_t *cuteTileset = cute_tiled_load_external_tileset(desc->path, NULL);
tileset.tiles = LoadTexture(desc->texturePath);
tileset.startID = cuteTileset->firstgid;
tileset.tileWidth = cuteTileset->tilewidth;
tileset.tileHeight = cuteTileset->tileheight;
tileset.offsetX = cuteTileset->tileoffset_x;
tileset.offsetY = cuteTileset->tileoffset_y;
tileset.width = tileset.tiles.width / tileset.tileWidth;
tileset.height = tileset.tiles.height / tileset.tileHeight;
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] = (BzTileShape) {BZ_TILE_SHAPE_NONE};
}
cute_tiled_tile_descriptor_t *cuteTile = cuteTileset->tiles;
for (; cuteTile; cuteTile = cuteTile->next) {
if (!cuteTile->objectgroup) continue;
cute_tiled_object_t *cuteObject = cuteTile->objectgroup->objects;
// NOTE: Only supporting single collider (integer values)
if (cuteObject) {
BzTileShape collider = bzCuteObjectToTileShape(cuteObject);
tileset.tileColliders[cuteTile->tile_index] = collider;
}
}
cute_tiled_free_external_tileset(cuteTileset);
if (tileset.tiles.width != cuteTileset->imagewidth ||
tileset.tiles.height != cuteTileset->imageheight) {
bzTilesetDestroy(&tileset);
return BZ_TILESET_INVALID;
}
tileset.isValid = true;
return tileset;
}
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) {
tileID = tileID - tileset->startID;
if (tileID < 0 || tileID >= tileset->tileCount) {
return (Rectangle){};
}
int posX = tileID % tileset->width;
int posY = tileID / tileset->width;
return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight,
tileset->tileWidth, tileset->tileHeight};
}
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID) {
tileID = tileID - tileset->startID;
if (tileID < 0 || tileID >= tileset->tileCount) {
return (BzTileShape) {.type = BZ_TILE_SHAPE_NONE};
}
return tileset->tileColliders[tileID];
}
void bzTilesetDestroy(BzTileset *tileset) {
UnloadTexture(tileset->tiles);
*tileset = BZ_TILESET_INVALID;
}

View File

@@ -0,0 +1,54 @@
#ifndef BREEZE_TILESET_H
#define BREEZE_TILESET_H
#include "../defines.h"
#include <raylib.h>
typedef struct BzTilesetDesc {
const char *path;
const char *texturePath;
} BzTilesetDesc;
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 BzTileShape {
BzTileShapeType type;
f32 x;
f32 y;
f32 sizeX;
f32 sizeY;
} BzTileShape;
typedef struct BzTileset {
Texture2D tiles;
i32 tileCount;
BzTileShape *tileColliders;
i32 startID;
i32 tileWidth;
i32 tileHeight;
i32 width;
i32 height;
i32 offsetX;
i32 offsetY;
bool isValid;
} BzTileset;
extern BzTileset BZ_TILESET_INVALID;
BzTileset bzTilesetCreate(const BzTilesetDesc *desc);
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID);
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID);
void bzTilesetDestroy(BzTileset *tileset);
#endif //BREEZE_TILESET_H