178 lines
4.5 KiB
C
178 lines
4.5 KiB
C
/**
|
|
* 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 "rpg/entity/entity.h"
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
uint32_t tileCount;
|
|
uint8_t modelCount;
|
|
uint8_t entityCount;
|
|
} assetchunkheader_t;
|
|
#pragma pack(pop)
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
tile_t tile;
|
|
} assetchunktiledata_t;
|
|
#pragma pack(pop)
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
uint32_t vertexCount;
|
|
} assetchunkmodelheader_t;
|
|
#pragma pack(pop)
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
entitytype_t entityType;
|
|
uint8_t localX;
|
|
uint8_t localY;
|
|
uint8_t localZ;
|
|
} assetchunkentityheader_t;
|
|
#pragma pack(pop)
|
|
|
|
errorret_t assetChunkLoad(assetcustom_t custom) {
|
|
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
|
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
|
|
|
chunk_t *chunk = (chunk_t *)custom.output;
|
|
assertTrue(chunk->meshCount == 0, "Chunk is not in a good state");
|
|
|
|
// Read header
|
|
assetchunkheader_t header;
|
|
size_t bytesRead = zip_fread(
|
|
custom.zipFile, &header, sizeof(assetchunkheader_t)
|
|
);
|
|
if(bytesRead != sizeof(assetchunkheader_t)) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Failed to read chunk asset header.");
|
|
}
|
|
|
|
if(header.tileCount != CHUNK_TILE_COUNT) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow(
|
|
"Chunk asset has invalid tile count: %d (expected %d).",
|
|
header.tileCount,
|
|
CHUNK_TILE_COUNT
|
|
);
|
|
}
|
|
|
|
if(header.modelCount > CHUNK_MESH_COUNT_MAX) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow(
|
|
"Chunk asset has too many models: %d (max %d).",
|
|
header.modelCount,
|
|
CHUNK_MESH_COUNT_MAX
|
|
);
|
|
}
|
|
|
|
if(header.entityCount > CHUNK_ENTITY_COUNT_MAX) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow(
|
|
"Chunk asset has too many entities: %d (max %d).",
|
|
header.entityCount,
|
|
CHUNK_ENTITY_COUNT_MAX
|
|
);
|
|
}
|
|
|
|
chunk->meshCount = header.modelCount;
|
|
|
|
// Read tile data
|
|
bytesRead = zip_fread(
|
|
custom.zipFile,
|
|
chunk->tiles,
|
|
sizeof(assetchunktiledata_t) * header.tileCount
|
|
);
|
|
if(bytesRead != sizeof(assetchunktiledata_t) * header.tileCount) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Failed to read chunk tile data.");
|
|
}
|
|
|
|
// For each model...
|
|
uint32_t vertexIndex = 0;
|
|
for(uint8_t i = 0; i < header.modelCount; i++) {
|
|
assetchunkmodelheader_t modelHeader;
|
|
bytesRead = zip_fread(
|
|
custom.zipFile, &modelHeader, sizeof(assetchunkmodelheader_t)
|
|
);
|
|
if(bytesRead != sizeof(assetchunkmodelheader_t)) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Failed to read chunk model header.");
|
|
}
|
|
|
|
if(
|
|
vertexIndex + modelHeader.vertexCount >
|
|
CHUNK_VERTEX_COUNT_MAX
|
|
) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Chunk model vertex count exceeds maximum.");
|
|
}
|
|
|
|
// Read vertex data.
|
|
bytesRead = zip_fread(
|
|
custom.zipFile,
|
|
&chunk->vertices[vertexIndex],
|
|
sizeof(meshvertex_t) * modelHeader.vertexCount
|
|
);
|
|
if(bytesRead != sizeof(meshvertex_t) * modelHeader.vertexCount) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Failed to read chunk model vertex data.");
|
|
}
|
|
|
|
// Init the mesh
|
|
if(modelHeader.vertexCount > 0) {
|
|
mesh_t *mesh = &chunk->meshes[i];
|
|
meshInit(
|
|
mesh,
|
|
MESH_PRIMITIVE_TRIANGLES,
|
|
modelHeader.vertexCount,
|
|
&chunk->vertices[vertexIndex]
|
|
);
|
|
|
|
vertexIndex += modelHeader.vertexCount;
|
|
} else {
|
|
chunk->meshes[i].vertexCount = 0;
|
|
}
|
|
}
|
|
|
|
// Read entity data
|
|
for(uint8_t i = 0; i < header.entityCount; i++) {
|
|
assetchunkentityheader_t entityHeader;
|
|
bytesRead = zip_fread(
|
|
custom.zipFile, &entityHeader, sizeof(assetchunkentityheader_t)
|
|
);
|
|
if(bytesRead != sizeof(assetchunkentityheader_t)) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("Failed to read chunk entity header.");
|
|
}
|
|
|
|
uint8_t entityIndex = entityGetAvailable();
|
|
if(entityIndex == 0xFF) {
|
|
zip_fclose(custom.zipFile);
|
|
errorThrow("No available entity slots.");
|
|
}
|
|
|
|
entity_t *entity = &ENTITIES[entityIndex];
|
|
entityInit(entity, (entitytype_t)entityHeader.entityType);
|
|
entity->position.x = (
|
|
(chunk->position.x * CHUNK_WIDTH) + entityHeader.localX
|
|
);
|
|
entity->position.y = (
|
|
(chunk->position.y * CHUNK_HEIGHT) + entityHeader.localY
|
|
);
|
|
entity->position.z = (
|
|
(chunk->position.z * CHUNK_DEPTH) + entityHeader.localZ
|
|
);
|
|
|
|
chunk->entities[i] = entityIndex;
|
|
}
|
|
|
|
errorOk();
|
|
} |