148 lines
4.4 KiB
C
148 lines
4.4 KiB
C
/**
|
|
* Copyright (c) 2026 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "assetmeshloader.h"
|
|
#include "assert/assert.h"
|
|
#include "util/endian.h"
|
|
#include "util/memory.h"
|
|
#include "asset/loader/assetloading.h"
|
|
#include "asset/loader/assetentry.h"
|
|
|
|
errorret_t assetMeshLoaderSync(assetloading_t *loading) {
|
|
assertNotNull(loading, "Loading cannot be NULL");
|
|
assertTrue(loading->type == ASSET_LOADER_TYPE_MESH, "Invalid type.");
|
|
|
|
assetmeshoutput_t *out = &loading->entry->data.mesh;
|
|
assetfile_t *file = &loading->loading.mesh.file;
|
|
assetmeshinputaxis_t axis = loading->entry->input->mesh;
|
|
|
|
assetLoaderErrorChain(loading, assetFileInit(
|
|
file, loading->entry->name, NULL, NULL
|
|
));
|
|
assetLoaderErrorChain(loading, assetFileOpen(file));
|
|
|
|
// Skip the 80-byte STL header
|
|
assetLoaderErrorChain(loading, assetFileRead(file, NULL, 80));
|
|
if(file->lastRead != 80) {
|
|
assetLoaderErrorThrow(loading, "Failed to skip STL header.");
|
|
}
|
|
|
|
uint32_t triangleCount;
|
|
assetLoaderErrorChain(
|
|
loading, assetFileRead(file, &triangleCount, sizeof(uint32_t))
|
|
);
|
|
if(file->lastRead != sizeof(uint32_t)) {
|
|
assetLoaderErrorThrow(loading, "Failed to read tri count");
|
|
}
|
|
triangleCount = endianLittleToHost32(triangleCount);
|
|
|
|
out->vertices = memoryAllocate(sizeof(meshvertex_t) * triangleCount * 3);
|
|
meshvertex_t *verts = out->vertices;
|
|
|
|
errorret_t ret;
|
|
for(uint32_t i = 0; i < triangleCount; i++) {
|
|
assetmeshstltriangle_t triData;
|
|
ret = assetFileRead(file, &triData, sizeof(triData));
|
|
if(ret.code != ERROR_OK) {
|
|
memoryFree(verts);
|
|
out->vertices = NULL;
|
|
assetLoaderErrorChain(loading, ret);
|
|
}
|
|
if(file->lastRead != sizeof(triData)) {
|
|
memoryFree(verts);
|
|
out->vertices = NULL;
|
|
assetLoaderErrorThrow(loading, "Failed to read triangle data");
|
|
}
|
|
|
|
for(uint8_t j = 0; j < 3; j++) {
|
|
#if MESH_ENABLE_COLOR
|
|
verts[i * 3 + j].color.r = (
|
|
(uint8_t)(endianLittleToHostFloat(triData.normal[0]) * 255.0f)
|
|
);
|
|
verts[i * 3 + j].color.g = (
|
|
(uint8_t)(endianLittleToHostFloat(triData.normal[1]) * 255.0f)
|
|
);
|
|
verts[i * 3 + j].color.b = (
|
|
(uint8_t)(endianLittleToHostFloat(triData.normal[2]) * 255.0f)
|
|
);
|
|
verts[i * 3 + j].color.a = 0xFF;
|
|
#endif
|
|
|
|
verts[i * 3 + j].uv[0] = 0.0f;
|
|
verts[i * 3 + j].uv[1] = 0.0f;
|
|
|
|
for(uint8_t k = 0; k < 3; k++) {
|
|
verts[i * 3 + j].pos[k] = endianLittleToHostFloat(
|
|
triData.positions[j][k]
|
|
);
|
|
}
|
|
|
|
switch(axis) {
|
|
case MESH_INPUT_AXIS_Z_UP: {
|
|
float_t temp = verts[i * 3 + j].pos[1];
|
|
verts[i * 3 + j].pos[1] = verts[i * 3 + j].pos[2];
|
|
verts[i * 3 + j].pos[2] = temp;
|
|
break;
|
|
}
|
|
case MESH_INPUT_AXIS_X_UP: {
|
|
float_t temp = verts[i * 3 + j].pos[0];
|
|
verts[i * 3 + j].pos[0] = verts[i * 3 + j].pos[1];
|
|
verts[i * 3 + j].pos[1] = temp;
|
|
break;
|
|
}
|
|
case MESH_INPUT_AXIS_Y_DOWN:
|
|
verts[i * 3 + j].pos[1] = -verts[i * 3 + j].pos[1];
|
|
break;
|
|
case MESH_INPUT_AXIS_Z_DOWN: {
|
|
float_t temp = verts[i * 3 + j].pos[1];
|
|
verts[i * 3 + j].pos[1] = -verts[i * 3 + j].pos[2];
|
|
verts[i * 3 + j].pos[2] = temp;
|
|
break;
|
|
}
|
|
case MESH_INPUT_AXIS_X_DOWN: {
|
|
float_t temp = verts[i * 3 + j].pos[0];
|
|
verts[i * 3 + j].pos[0] = verts[i * 3 + j].pos[1];
|
|
verts[i * 3 + j].pos[1] = -temp;
|
|
break;
|
|
}
|
|
case MESH_INPUT_AXIS_Y_UP:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = assetFileClose(file);
|
|
if(ret.code != ERROR_OK) {
|
|
memoryFree(verts);
|
|
out->vertices = NULL;
|
|
assetLoaderErrorChain(loading, ret);
|
|
}
|
|
assetFileDispose(file);
|
|
|
|
ret = meshInit(
|
|
&out->mesh, MESH_PRIMITIVE_TYPE_TRIANGLES, triangleCount * 3, verts
|
|
);
|
|
if(ret.code != ERROR_OK) {
|
|
loading->entry->state = ASSET_ENTRY_STATE_ERROR;
|
|
memoryFree(verts);
|
|
out->vertices = NULL;
|
|
assetLoaderErrorChain(loading, ret);
|
|
}
|
|
|
|
loading->entry->state = ASSET_ENTRY_STATE_LOADED;
|
|
errorOk();
|
|
}
|
|
|
|
errorret_t assetMeshDispose(assetentry_t *entry) {
|
|
assertNotNull(entry, "Asset entry cannot be NULL");
|
|
assertTrue(entry->type == ASSET_LOADER_TYPE_MESH, "Invalid type.");
|
|
errorChain(meshDispose(&entry->data.mesh.mesh));
|
|
memoryFree(entry->data.mesh.vertices);
|
|
errorOk();
|
|
}
|