Prepping map stuff
This commit is contained in:
@@ -3,4 +3,4 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_asset(MAP untitled.tmx)
|
add_asset(MAP map.json)
|
||||||
6
assets/map/map.json
Normal file
6
assets/map/map.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"tiles": [
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 1
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<map version="1.10" tiledversion="1.11.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
|
|
||||||
<tileset firstgid="1" source="../tileset/prarie.tsx"/>
|
|
||||||
<layer id="1" name="Tile Layer 1" width="30" height="20">
|
|
||||||
<data encoding="csv">
|
|
||||||
2,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
9,10,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
</data>
|
|
||||||
</layer>
|
|
||||||
</map>
|
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "type/assetpaletteimage.h"
|
#include "type/assetpaletteimage.h"
|
||||||
#include "type/assetalphaimage.h"
|
#include "type/assetalphaimage.h"
|
||||||
#include "type/assetlanguage.h"
|
#include "type/assetlanguage.h"
|
||||||
|
#include "type/assetmap.h"
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -17,6 +18,7 @@ typedef enum {
|
|||||||
ASSET_TYPE_PALETTE_IMAGE,
|
ASSET_TYPE_PALETTE_IMAGE,
|
||||||
ASSET_TYPE_ALPHA_IMAGE,
|
ASSET_TYPE_ALPHA_IMAGE,
|
||||||
ASSET_TYPE_LANGUAGE,
|
ASSET_TYPE_LANGUAGE,
|
||||||
|
ASSET_TYPE_MAP,
|
||||||
|
|
||||||
ASSET_TYPE_COUNT,
|
ASSET_TYPE_COUNT,
|
||||||
} assettype_t;
|
} assettype_t;
|
||||||
@@ -64,5 +66,12 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
|||||||
.header = "DLF",
|
.header = "DLF",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetLanguageHandler
|
.custom = assetLanguageHandler
|
||||||
|
},
|
||||||
|
|
||||||
|
[ASSET_TYPE_MAP] = {
|
||||||
|
.header = "DMF",
|
||||||
|
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||||
|
.dataSize = sizeof(assetmap_t),
|
||||||
|
.entire = assetMapLoad
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -9,4 +9,5 @@ target_sources(${DUSK_TARGET_NAME}
|
|||||||
assetalphaimage.c
|
assetalphaimage.c
|
||||||
assetpaletteimage.c
|
assetpaletteimage.c
|
||||||
assetlanguage.c
|
assetlanguage.c
|
||||||
|
assetmap.c
|
||||||
)
|
)
|
||||||
33
src/asset/type/assetmap.c
Normal file
33
src/asset/type/assetmap.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
errorret_t assetMapLoad(void *data, void *output) {
|
||||||
|
assertNotNull(data, "Data cannot be NULL");
|
||||||
|
assertNotNull(output, "Output cannot be NULL");
|
||||||
|
|
||||||
|
assetmap_t *mapData = (assetmap_t *)data;
|
||||||
|
assetmapmodel_t *mesh = (assetmapmodel_t *)output;
|
||||||
|
|
||||||
|
memoryCopy(
|
||||||
|
mesh,
|
||||||
|
&mapData->models[0],
|
||||||
|
sizeof(assetmapmodel_t)
|
||||||
|
);
|
||||||
|
|
||||||
|
meshInit(
|
||||||
|
&mesh->mesh,
|
||||||
|
MESH_PRIMITIVE_TRIANGLES,
|
||||||
|
mesh->vertexCount,
|
||||||
|
mesh->vertices
|
||||||
|
);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
35
src/asset/type/assetmap.h
Normal file
35
src/asset/type/assetmap.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "rpg/world/map.h"
|
||||||
|
#include "display/mesh/mesh.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t vertexCount;
|
||||||
|
meshvertex_t vertices[36];
|
||||||
|
mesh_t mesh;
|
||||||
|
} assetmapmodel_t;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t tileCount;
|
||||||
|
uint8_t modelCount;
|
||||||
|
tile_t tiles[CHUNK_TILE_COUNT];
|
||||||
|
assetmapmodel_t models[1];
|
||||||
|
} assetmap_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a map asset from the given data pointer into the output map structure.
|
||||||
|
*
|
||||||
|
* @param data Pointer to the raw assetmap_t data.
|
||||||
|
* @param output Pointer to the map_t to load the map into.
|
||||||
|
* @return An error code.
|
||||||
|
*/
|
||||||
|
errorret_t assetMapLoad(void *data, void *output);
|
||||||
@@ -81,9 +81,11 @@ void entityWalk(entity_t *entity, const entitydir_t direction) {
|
|||||||
// Check one level down for walkable tile (stairs down)
|
// Check one level down for walkable tile (stairs down)
|
||||||
worldpos_t belowPos = newPos;
|
worldpos_t belowPos = newPos;
|
||||||
belowPos.z -= 1;
|
belowPos.z -= 1;
|
||||||
tile = mapGetTile(belowPos);
|
tile_t belowTile = mapGetTile(belowPos);
|
||||||
|
|
||||||
if(tile != TILE_NULL) newPos.z -= 1;
|
if(belowTile == TILE_STAIRS_UP) {
|
||||||
|
tile = TILE_STAIRS_DOWN;// Mark current as stairs down
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tile walkable?
|
// Tile walkable?
|
||||||
@@ -98,11 +100,19 @@ void entityWalk(entity_t *entity, const entitydir_t direction) {
|
|||||||
return;// Blocked
|
return;// Blocked
|
||||||
} while(++other, other < &ENTITIES[ENTITY_COUNT]);
|
} while(++other, other < &ENTITIES[ENTITY_COUNT]);
|
||||||
|
|
||||||
|
entity->lastPosition = entity->position;
|
||||||
entity->position = newPos;
|
entity->position = newPos;
|
||||||
entity->animation = ENTITY_ANIM_WALK;
|
entity->animation = ENTITY_ANIM_WALK;
|
||||||
entity->animTime = ENTITY_ANIM_WALK_DURATION;// TODO: Running vs walking
|
entity->animTime = ENTITY_ANIM_WALK_DURATION;// TODO: Running vs walking
|
||||||
|
|
||||||
// We are comitting, we can run effects here.
|
// We are comitting, we can run effects here.
|
||||||
|
if(tile == TILE_STAIRS_DOWN) {
|
||||||
|
// Moving down a level
|
||||||
|
entity->position.z -= 1;
|
||||||
|
} else if(tile == TILE_STAIRS_UP) {
|
||||||
|
// Moving up a level
|
||||||
|
entity->position.z += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_t * entityGetAt(const worldpos_t position) {
|
entity_t * entityGetAt(const worldpos_t position) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ typedef struct entity_s {
|
|||||||
// Movement
|
// Movement
|
||||||
entitydir_t direction;
|
entitydir_t direction;
|
||||||
worldpos_t position;
|
worldpos_t position;
|
||||||
|
worldpos_t lastPosition;
|
||||||
|
|
||||||
entityanim_t animation;
|
entityanim_t animation;
|
||||||
float_t animTime;
|
float_t animTime;
|
||||||
|
|||||||
@@ -128,12 +128,25 @@ void mapChunkLoad(chunk_t* chunk) {
|
|||||||
memoryZero(chunk->tiles, sizeof(tile_t) * CHUNK_TILE_COUNT);
|
memoryZero(chunk->tiles, sizeof(tile_t) * CHUNK_TILE_COUNT);
|
||||||
|
|
||||||
// 3x3 test walkable area
|
// 3x3 test walkable area
|
||||||
for(int y = 0; y <= 3; y++) {
|
chunktileindex_t x, y, z;
|
||||||
for(int x = 0; x <= 3; x++) {
|
|
||||||
|
z = 0;
|
||||||
|
for(y = 0; y <= 3; y++) {
|
||||||
|
for(x = 0; x <= 3; x++) {
|
||||||
chunktileindex_t tileIndex = (y * CHUNK_WIDTH) + x;
|
chunktileindex_t tileIndex = (y * CHUNK_WIDTH) + x;
|
||||||
chunk->tiles[tileIndex] = TILE_WALKABLE;
|
chunk->tiles[tileIndex] = TILE_WALKABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x = 3, y = 3;
|
||||||
|
chunk->tiles[(z * CHUNK_WIDTH * CHUNK_HEIGHT) + (y * CHUNK_WIDTH) + x] = TILE_STAIRS_UP;
|
||||||
|
|
||||||
|
// x = 3, y = 2, z = 1;
|
||||||
|
// chunk->tiles[(z * CHUNK_WIDTH * CHUNK_HEIGHT) + (y * CHUNK_WIDTH) + x] = TILE_WALKABLE;
|
||||||
|
// x = 2, y = 2, z = 1;
|
||||||
|
// chunk->tiles[(z * CHUNK_WIDTH * CHUNK_HEIGHT) + (y * CHUNK_WIDTH) + x] = TILE_WALKABLE;
|
||||||
|
// x = 4, y = 2, z = 1;
|
||||||
|
// chunk->tiles[(z * CHUNK_WIDTH * CHUNK_HEIGHT) + (y * CHUNK_WIDTH) + x] = TILE_WALKABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) {
|
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) {
|
||||||
|
|||||||
@@ -8,5 +8,9 @@
|
|||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
|
||||||
bool_t tileIsWalkable(const tile_t tile) {
|
bool_t tileIsWalkable(const tile_t tile) {
|
||||||
return tile == TILE_WALKABLE;
|
return (
|
||||||
|
tile == TILE_WALKABLE ||
|
||||||
|
tile == TILE_STAIRS_UP ||
|
||||||
|
tile == TILE_STAIRS_DOWN
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,8 @@ typedef uint8_t tile_t;
|
|||||||
|
|
||||||
#define TILE_NULL 0
|
#define TILE_NULL 0
|
||||||
#define TILE_WALKABLE 1
|
#define TILE_WALKABLE 1
|
||||||
|
#define TILE_STAIRS_UP 2
|
||||||
|
#define TILE_STAIRS_DOWN 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the given tile is walkable.
|
* Returns whether or not the given tile is walkable.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
typedef int16_t worldunit_t;
|
typedef int16_t worldunit_t;
|
||||||
typedef int16_t chunkunit_t;
|
typedef int16_t chunkunit_t;
|
||||||
typedef int16_t chunkindex_t;
|
typedef int16_t chunkindex_t;
|
||||||
typedef uint8_t chunktileindex_t;
|
typedef uint32_t chunktileindex_t;
|
||||||
|
|
||||||
typedef int32_t worldunits_t;
|
typedef int32_t worldunits_t;
|
||||||
typedef int32_t chunkunits_t;
|
typedef int32_t chunkunits_t;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "scene/scenedata.h"
|
#include "scene/scenedata.h"
|
||||||
#include "display/spritebatch.h"
|
#include "display/spritebatch.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
#include "rpg/world/map.h"
|
#include "rpg/world/map.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
|
||||||
#define TILE_SIZE 16
|
#define TILE_SIZE 16
|
||||||
|
assetmapmodel_t mesh;
|
||||||
|
|
||||||
errorret_t sceneMapInit(scenedata_t *data) {
|
errorret_t sceneMapInit(scenedata_t *data) {
|
||||||
// Init the camera.
|
// Init the camera.
|
||||||
@@ -34,6 +36,8 @@ errorret_t sceneMapInit(scenedata_t *data) {
|
|||||||
);
|
);
|
||||||
data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = 1.0f;
|
data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = 1.0f;
|
||||||
|
|
||||||
|
|
||||||
|
errorChain(assetLoad("map/map.dmf", &mesh));
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,15 +65,18 @@ void sceneMapEntityGetPosition(const entity_t *entity, vec3 outPosition) {
|
|||||||
float_t animPercentage = entity->animTime / ENTITY_ANIM_WALK_DURATION;
|
float_t animPercentage = entity->animTime / ENTITY_ANIM_WALK_DURATION;
|
||||||
|
|
||||||
// Get facing rel, we know we moved from the inverse direction.
|
// Get facing rel, we know we moved from the inverse direction.
|
||||||
worldunits_t x, y;
|
|
||||||
entityDirGetRelative(entity->direction, &x, &y);
|
|
||||||
x = -x, y = -y;
|
|
||||||
|
|
||||||
// Add tile size times percentage to posMin/max
|
// Add tile size times percentage to posMin/max
|
||||||
vec3 offset = {
|
vec3 offset = {
|
||||||
x * TILE_SIZE * animPercentage,
|
(
|
||||||
y * TILE_SIZE * animPercentage,
|
(float_t)entity->position.x - (float_t)entity->lastPosition.x
|
||||||
0.0f
|
) * TILE_SIZE * -animPercentage,
|
||||||
|
(
|
||||||
|
(float_t)entity->position.y - (float_t)entity->lastPosition.y
|
||||||
|
) * TILE_SIZE * -animPercentage,
|
||||||
|
(
|
||||||
|
(float_t)entity->position.z - (float_t)entity->lastPosition.z
|
||||||
|
) * TILE_SIZE * -animPercentage
|
||||||
};
|
};
|
||||||
glm_vec3_add(outPosition, offset, outPosition);
|
glm_vec3_add(outPosition, offset, outPosition);
|
||||||
break;
|
break;
|
||||||
@@ -107,7 +114,10 @@ void sceneMapRender(scenedata_t *data) {
|
|||||||
cameraPushMatrix(&data->sceneMap.camera);
|
cameraPushMatrix(&data->sceneMap.camera);
|
||||||
|
|
||||||
// Render map probably.
|
// Render map probably.
|
||||||
sceneMapRenderMap();
|
// sceneMapRenderMap();
|
||||||
|
|
||||||
|
textureBind(NULL);
|
||||||
|
meshDraw(&mesh.mesh, -1, -1);
|
||||||
|
|
||||||
// Render ents
|
// Render ents
|
||||||
entity_t *ent = ENTITIES;
|
entity_t *ent = ENTITIES;
|
||||||
@@ -125,11 +135,10 @@ void sceneMapRenderEntity(entity_t *entity) {
|
|||||||
|
|
||||||
if(entity->type == ENTITY_TYPE_NULL) return;
|
if(entity->type == ENTITY_TYPE_NULL) return;
|
||||||
|
|
||||||
vec3 posCenter, posMin, posMax;
|
vec3 posMin, posMax;
|
||||||
vec3 halfSize = { TILE_SIZE / 2.0f, TILE_SIZE / 2.0f, TILE_SIZE / 2.0f };
|
vec3 size = { TILE_SIZE, TILE_SIZE, TILE_SIZE };
|
||||||
sceneMapEntityGetPosition(entity, posCenter);
|
sceneMapEntityGetPosition(entity, posMin);
|
||||||
glm_vec3_sub(posCenter, halfSize, posMin);
|
glm_vec3_add(posMin, size, posMax);
|
||||||
glm_vec3_add(posCenter, halfSize, posMax);
|
|
||||||
|
|
||||||
// TEST: Change color depending on dir.
|
// TEST: Change color depending on dir.
|
||||||
color_t testColor;
|
color_t testColor;
|
||||||
@@ -167,11 +176,6 @@ void sceneMapRenderMap() {
|
|||||||
min[1] = chunk->position.y * CHUNK_HEIGHT * TILE_SIZE;
|
min[1] = chunk->position.y * CHUNK_HEIGHT * TILE_SIZE;
|
||||||
min[2] = chunk->position.z * CHUNK_DEPTH * TILE_SIZE;
|
min[2] = chunk->position.z * CHUNK_DEPTH * TILE_SIZE;
|
||||||
|
|
||||||
// center tile
|
|
||||||
min[0] -= TILE_SIZE / 2.0f;
|
|
||||||
min[1] -= TILE_SIZE / 2.0f;
|
|
||||||
min[2] -= TILE_SIZE / 2.0f;
|
|
||||||
|
|
||||||
max[0] = min[0] + (CHUNK_WIDTH * TILE_SIZE);
|
max[0] = min[0] + (CHUNK_WIDTH * TILE_SIZE);
|
||||||
max[1] = min[1] + (CHUNK_HEIGHT * TILE_SIZE);
|
max[1] = min[1] + (CHUNK_HEIGHT * TILE_SIZE);
|
||||||
max[2] = min[2];
|
max[2] = min[2];
|
||||||
@@ -195,4 +199,5 @@ void sceneMapRenderMap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sceneMapDispose(scenedata_t *data) {
|
void sceneMapDispose(scenedata_t *data) {
|
||||||
|
meshDispose(&mesh.mesh);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ bool_t UI_DEBUG_DRAW = true;
|
|||||||
void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
||||||
if(!UI_DEBUG_DRAW) return;
|
if(!UI_DEBUG_DRAW) return;
|
||||||
|
|
||||||
char_t buffer[96];
|
char_t buffer[128];
|
||||||
color_t color;
|
color_t color;
|
||||||
int32_t w, h, hOffset = 0;
|
int32_t w, h, hOffset = 0;
|
||||||
|
|
||||||
@@ -64,6 +64,7 @@ void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
|||||||
);
|
);
|
||||||
hOffset += h;
|
hOffset += h;
|
||||||
|
|
||||||
|
|
||||||
// Player position
|
// Player position
|
||||||
entity_t *player = NULL;
|
entity_t *player = NULL;
|
||||||
for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
||||||
@@ -77,9 +78,10 @@ void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
|||||||
snprintf(
|
snprintf(
|
||||||
buffer,
|
buffer,
|
||||||
sizeof(buffer),
|
sizeof(buffer),
|
||||||
"%d,%d/%d/%d",
|
"%d,%d,%d/%d/%d",
|
||||||
player->position.x,
|
player->position.x,
|
||||||
player->position.y,
|
player->position.y,
|
||||||
|
player->position.z,
|
||||||
(int32_t)player->direction,
|
(int32_t)player->direction,
|
||||||
(int32_t)player->animation
|
(int32_t)player->animation
|
||||||
);
|
);
|
||||||
@@ -87,7 +89,7 @@ void uiDebugRender(const tileset_t *tileset, texture_t *texture) {
|
|||||||
uiTextMeasure(buffer, tileset, &w, &h);
|
uiTextMeasure(buffer, tileset, &w, &h);
|
||||||
uiTextDraw(
|
uiTextDraw(
|
||||||
SCREEN.width - w, hOffset,
|
SCREEN.width - w, hOffset,
|
||||||
buffer, COLOR_WHITE, tileset, texture
|
buffer, COLOR_GREEN, tileset, texture
|
||||||
);
|
);
|
||||||
hOffset += h;
|
hOffset += h;
|
||||||
|
|
||||||
|
|||||||
@@ -1,143 +1,124 @@
|
|||||||
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
from args import args
|
from args import args
|
||||||
from xml.etree import ElementTree as ET
|
|
||||||
from processtileset import processTileset
|
|
||||||
from assetcache import assetCache, assetGetCache
|
from assetcache import assetCache, assetGetCache
|
||||||
from assethelpers import getAssetRelativePath
|
from assethelpers import getAssetRelativePath
|
||||||
|
|
||||||
|
CHUNK_WIDTH = 16
|
||||||
|
CHUNK_HEIGHT = 16
|
||||||
|
CHUNK_DEPTH = 32
|
||||||
|
CHUNK_TILE_COUNT = CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH
|
||||||
|
TILE_SIZE = 16.0
|
||||||
|
|
||||||
|
def createQuadForTile(model, tileIndex, x=0, y=0, z=0):
|
||||||
|
# Only append vertices if z == 0
|
||||||
|
if z != 0:
|
||||||
|
return
|
||||||
|
# Determine color for checkerboard pattern
|
||||||
|
color = (255,255,255) if (x + y) % 2 == 0 else (0,0,0)
|
||||||
|
# Use TILE_SIZE for positions
|
||||||
|
px = x * TILE_SIZE
|
||||||
|
py = y * TILE_SIZE
|
||||||
|
pz = z * TILE_SIZE
|
||||||
|
quad_vertices = [
|
||||||
|
{'position': (px, py, pz), 'color': color, 'uv': (0,0)}, # 0,0
|
||||||
|
{'position': (px + TILE_SIZE, py, pz), 'color': color, 'uv': (1,0)}, # 1,0
|
||||||
|
{'position': (px + TILE_SIZE, py + TILE_SIZE, pz), 'color': color, 'uv': (1,1)}, # 1,1
|
||||||
|
{'position': (px, py, pz), 'color': color, 'uv': (0,0)}, # 0,0 (repeat)
|
||||||
|
{'position': (px + TILE_SIZE, py + TILE_SIZE, pz), 'color': color, 'uv': (1,1)}, # 1,1 (repeat)
|
||||||
|
{'position': (px, py + TILE_SIZE, pz), 'color': color, 'uv': (0,1)} # 0,1
|
||||||
|
]
|
||||||
|
base = len(model['vertices'])
|
||||||
|
quad_indices = [base, base+1, base+2, base+3, base+4, base+5]
|
||||||
|
model['vertices'].extend(quad_vertices)
|
||||||
|
model['indices'].extend(quad_indices)
|
||||||
|
model['vertexCount'] = len(model['vertices'])
|
||||||
|
model['indexCount'] = len(model['indices'])
|
||||||
|
|
||||||
def processMap(asset):
|
def processMap(asset):
|
||||||
cache = assetGetCache(asset['path'])
|
cache = assetGetCache(asset['path'])
|
||||||
if cache is not None:
|
if cache is not None:
|
||||||
return cache
|
return cache
|
||||||
|
|
||||||
# Load the TMX file
|
|
||||||
tree = ET.parse(asset['path'])
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
# Root needs to be "map" element.
|
|
||||||
if root.tag != 'map':
|
|
||||||
print(f"Error: TMX file {asset['path']} does not have a <map> root element")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Root needs to be orientation="orthogonal"
|
|
||||||
if 'orientation' not in root.attrib or root.attrib['orientation'] != 'orthogonal':
|
|
||||||
print(f"Error: TMX file {asset['path']} does not have orientation='orthogonal'")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Extract width, height, tilewidth, tileheight attributes
|
# Read input file as JSON
|
||||||
if 'width' not in root.attrib or 'height' not in root.attrib or 'tilewidth' not in root.attrib or 'tileheight' not in root.attrib:
|
with open(asset['path'], 'r') as f:
|
||||||
print(f"Error: TMX file {asset['path']} is missing required attributes (width, height, tilewidth, tileheight)")
|
inData = json.load(f)
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
mapWidth = int(root.attrib['width'])
|
|
||||||
mapHeight = int(root.attrib['height'])
|
|
||||||
tileWidth = int(root.attrib['tilewidth'])
|
|
||||||
tileHeight = int(root.attrib['tileheight'])
|
|
||||||
|
|
||||||
# Find all tileset elements
|
|
||||||
tilesets = []
|
|
||||||
for tilesetElement in root.findall('tileset'):
|
|
||||||
# Tileset must have a source attribute
|
|
||||||
if 'source' not in tilesetElement.attrib:
|
|
||||||
print(f"Error: <tileset> element in {asset['path']} is missing a source attribute")
|
|
||||||
sys.exit(1)
|
|
||||||
# Must have a firstgid attribute
|
|
||||||
if 'firstgid' not in tilesetElement.attrib:
|
|
||||||
print(f"Error: <tileset> element in {asset['path']} is missing a firstgid attribute")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
firstGid = int(tilesetElement.attrib['firstgid'])
|
|
||||||
source = tilesetElement.attrib['source']
|
|
||||||
|
|
||||||
# Get source path relative to the tmx file's working directory.
|
|
||||||
# Needs normalizing also since ".." is often used.
|
|
||||||
source = os.path.normpath(os.path.join(os.path.dirname(asset['path']), source))
|
|
||||||
tileset = processTileset({ 'path': source, 'type': 'tileset', 'options': {} })
|
|
||||||
|
|
||||||
tilesets.append({
|
|
||||||
'firstGid': firstGid,
|
|
||||||
'source': source,
|
|
||||||
'tileset': tileset
|
|
||||||
})
|
|
||||||
|
|
||||||
# Sort tilesets by firstGid, highest first
|
|
||||||
tilesets.sort(key=lambda x: x['firstGid'], reverse=True)
|
|
||||||
|
|
||||||
# Layer types
|
|
||||||
# objectLayers = [] # Not implemented
|
|
||||||
tileLayers = []
|
|
||||||
for layerElement in root.findall('layer'):
|
|
||||||
# Assume tile layer for now
|
|
||||||
# Must have id, name, width, height attributes
|
|
||||||
if 'id' not in layerElement.attrib or 'name' not in layerElement.attrib or 'width' not in layerElement.attrib or 'height' not in layerElement.attrib:
|
|
||||||
print(f"Error: <layer> element in {asset['path']} is missing required attributes (id, name, width, height)")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
id = int(layerElement.attrib['id'])
|
|
||||||
name = layerElement.attrib['name']
|
|
||||||
width = int(layerElement.attrib['width'])
|
|
||||||
height = int(layerElement.attrib['height'])
|
|
||||||
|
|
||||||
# Need exactly one data element
|
|
||||||
dataElements = layerElement.findall('data')
|
|
||||||
if len(dataElements) != 1:
|
|
||||||
print(f"Error: <layer> element in {asset['path']} must have exactly one <data> child element")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Get text, remove whitespace, split by comman and convert to int
|
|
||||||
dataElement = dataElements[0]
|
|
||||||
if dataElement.attrib.get('encoding', '') != 'csv':
|
|
||||||
print(f"Error: <data> element in {asset['path']} must have encoding='csv'")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
dataText = dataElement.text.strip()
|
|
||||||
data = [int(gid) for gid in dataText.split(',') if gid.strip().isdigit()]
|
|
||||||
|
|
||||||
# Should be exactly width * height entries
|
|
||||||
if len(data) != width * height:
|
|
||||||
print(f"Error: <data> element in {asset['path']} has {len(data)} entries but expected {width * height} (width * height)")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
tileLayers.append({
|
|
||||||
'id': id,
|
|
||||||
'name': name,
|
|
||||||
'width': width,
|
|
||||||
'height': height,
|
|
||||||
'data': data,
|
|
||||||
})
|
|
||||||
|
|
||||||
# Now we have our layers all parsed out.
|
|
||||||
data = bytearray()
|
|
||||||
data += b'DRM' # Dusk RPG Map
|
|
||||||
data += mapWidth.to_bytes(4, 'little') # Map width in tiles
|
|
||||||
data += mapHeight.to_bytes(4, 'little') # Map height in tiles
|
|
||||||
data += len(tilesets).to_bytes(4, 'little') # Number of tilesets
|
|
||||||
data += len(tileLayers).to_bytes(4, 'little') # Number of layers
|
|
||||||
|
|
||||||
# For each layer...
|
tileIndexes = inData['tiles']
|
||||||
for layer in tileLayers:
|
|
||||||
for gid in layer['data']:
|
|
||||||
data += gid.to_bytes(4, 'little') # Tileset index
|
|
||||||
|
|
||||||
# For each tileset
|
# Create output object 'map' with default tile indexes and models array
|
||||||
for tileset in tilesets:
|
map = {
|
||||||
data += tileset['firstGid'].to_bytes(4, 'little') # First GID
|
'tiles': [0] * CHUNK_TILE_COUNT,
|
||||||
data += tileset['tileset']['tilesetIndex'].to_bytes(4, 'little') # Tileset index
|
'models': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a simple 3D model object
|
||||||
|
model = {
|
||||||
|
'vertices': [],
|
||||||
|
'indices': [],
|
||||||
|
'vertexCount': 0,
|
||||||
|
'indexCount': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Append the model to map.models
|
||||||
|
map['models'].append(model)
|
||||||
|
|
||||||
|
for i, tile in enumerate(tileIndexes):
|
||||||
|
# Calculate x, y, z from i
|
||||||
|
x = i % CHUNK_WIDTH
|
||||||
|
y = (i // CHUNK_WIDTH) % CHUNK_HEIGHT
|
||||||
|
z = i // (CHUNK_WIDTH * CHUNK_HEIGHT)
|
||||||
|
createQuadForTile(model, tile, x, y, z)
|
||||||
|
|
||||||
|
# Generate binary buffer for efficient output
|
||||||
|
buffer = bytearray()
|
||||||
|
buffer.extend(b'DMF')# Header
|
||||||
|
buffer.extend(len(map['tiles']).to_bytes(4, 'little')) # Number of tiles
|
||||||
|
buffer.extend(len(map['models']).to_bytes(1, 'little')) # Number of models
|
||||||
|
|
||||||
|
# Buffer tile data as array of uint8_t
|
||||||
|
for tileIndex in map['tiles']:
|
||||||
|
buffer.append(tileIndex.to_bytes(1, 'little')[0])
|
||||||
|
|
||||||
|
# For each model
|
||||||
|
for model in map['models']:
|
||||||
|
# Write vertex count and index count
|
||||||
|
buffer.extend(model['vertexCount'].to_bytes(4, 'little'))
|
||||||
|
# buffer.extend(model['indexCount'].to_bytes(4, 'little'))
|
||||||
|
# For each vertex
|
||||||
|
for vertex in model['vertices']:
|
||||||
|
# This is not tightly packed in memory.
|
||||||
|
# R G B A U V X Y Z
|
||||||
|
# Color is 4 bytes (RGBA)
|
||||||
|
# Rest is floats
|
||||||
|
r, g, b = vertex['color']
|
||||||
|
a = 255
|
||||||
|
buffer.extend(r.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(g.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(b.to_bytes(1, 'little'))
|
||||||
|
buffer.extend(a.to_bytes(1, 'little'))
|
||||||
|
u, v = vertex['uv']
|
||||||
|
buffer.extend(bytearray(struct.pack('<f', u)))
|
||||||
|
buffer.extend(bytearray(struct.pack('<f', v)))
|
||||||
|
x, y, z = vertex['position']
|
||||||
|
buffer.extend(bytearray(struct.pack('<f', x)))
|
||||||
|
buffer.extend(bytearray(struct.pack('<f', y)))
|
||||||
|
buffer.extend(bytearray(struct.pack('<f', z)))
|
||||||
|
|
||||||
|
# Write out map file
|
||||||
relative = getAssetRelativePath(asset['path'])
|
relative = getAssetRelativePath(asset['path'])
|
||||||
fileNameWithoutExt = os.path.splitext(os.path.basename(asset['path']))[0]
|
fileNameWithoutExt = os.path.splitext(os.path.basename(asset['path']))[0]
|
||||||
outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.drm")
|
outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dmf")
|
||||||
outputFilePath = os.path.join(args.output_assets, outputFileRelative)
|
outputFilePath = os.path.join(args.output_assets, outputFileRelative)
|
||||||
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
|
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
|
||||||
with open(outputFilePath, "wb") as f:
|
with open(outputFilePath, "wb") as f:
|
||||||
f.write(data)
|
f.write(buffer)
|
||||||
|
|
||||||
outMap = {
|
outMap = {
|
||||||
'mapPath': outputFileRelative,
|
|
||||||
'files': [ outputFilePath ],
|
'files': [ outputFilePath ],
|
||||||
'width': mapWidth,
|
'map': map
|
||||||
'height': mapHeight,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return assetCache(asset['path'], outMap)
|
return assetCache(asset['path'], outMap)
|
||||||
Reference in New Issue
Block a user