Consistent

This commit is contained in:
2026-05-30 20:30:13 -05:00
parent 1cd6f4cb72
commit 6acfca6d48
9 changed files with 178 additions and 420 deletions
+98 -183
View File
@@ -1,212 +1,127 @@
/**
* Copyright (c) 2026 Dominic Masters
*
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/loader/display/assetmeshloader.h"
#include "asset/asset.h"
#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 assetMeshLoaderNEW(assetloading_t *loading) {
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;
assetmeshloaderparams_t params = {
.outMesh = &out->mesh,
.outVertices = &out->vertices,
.inputAxis = loading->entry->input->mesh
};
errorChain(assetFileInit(file, loading->entry->name, NULL, NULL));
errorChain(assetFileOpen(file));
errorChain(assetFileInit(file, loading->entry->name, NULL, &params));
errorChain(assetMeshLoader(file));
// Skip the 80-byte STL header
errorChain(assetFileRead(file, NULL, 80));
if(file->lastRead != 80) errorThrow("Failed to skip STL header");
uint32_t triangleCount;
errorChain(assetFileRead(file, &triangleCount, sizeof(uint32_t)));
if(file->lastRead != sizeof(uint32_t)) errorThrow("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;
errorChain(ret);
}
if(file->lastRead != sizeof(triData)) {
memoryFree(verts);
out->vertices = NULL;
errorThrow("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;
errorChain(ret);
}
assetFileDispose(file);
ret = meshInit(&out->mesh, MESH_PRIMITIVE_TYPE_TRIANGLES, triangleCount * 3, verts);
if(ret.code != ERROR_OK) {
memoryFree(verts);
out->vertices = NULL;
errorChain(ret);
}
errorOk();
}
errorret_t assetMeshDisposeNEW(assetentry_t *entry) {
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();
}
errorret_t assetMeshLoader(assetfile_t *file) {
assertNotNull(file, "Asset file cannot be null");
assetmeshloaderparams_t *output = (assetmeshloaderparams_t *)file->output;
assertNotNull(output, "Output cannot be null");
assertNotNull(output->outMesh, "Output mesh cannot be null");
assertNotNull(output->outVertices, "Output vertices cannot be null");
// STL file loading
errorChain(assetFileOpen(file));
// Skip the 80 byte header
errorChain(assetFileRead(file, NULL, 80));
if(file->lastRead != 80) errorThrow("Failed to skip STL header");
uint32_t triangleCount;
errorChain(assetFileRead(file, &triangleCount, sizeof(uint32_t)));
if(file->lastRead != sizeof(uint32_t)) errorThrow("Failed read tri count");
// normalize
triangleCount = endianLittleToHost32(triangleCount);
// Allocate mesh and vertex data
errorret_t ret;
meshvertex_t *verts = memoryAllocate(
sizeof(meshvertex_t) * triangleCount * 3
);
*output->outVertices = verts;
// Read triangle data
for(uint32_t i = 0; i < triangleCount; i++) {
assetmeshstltriangle_t triData;
ret = assetFileRead(file, &triData, sizeof(triData));
if(ret.code != ERROR_OK) {
memoryFree(verts);
errorChain(ret);
}
if(file->lastRead != sizeof(triData)) {
memoryFree(verts);
errorThrow("Failed to read triangle data");
}
// Skip normals, we don't use them
// Fix endianess of of 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; // No UV data in STL, just set to 0
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(output->inputAxis) {
case MESH_INPUT_AXIS_Z_UP:
// Convert Z-Up to Y-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:
// Convert X-Up to Y-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:
// Invert Y axis
verts[i * 3 + j].pos[1] = -verts[i * 3 + j].pos[1];
break;
case MESH_INPUT_AXIS_Z_DOWN:
// Convert Z-Up to Y-Up and invert Y axis
{
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:
// Convert X-Up to Y-Up and invert Y axis
{
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:
// No covnersion possible / Needed
break;
}
}
}
// Finally, init mesh
ret = meshInit(
output->outMesh,
MESH_PRIMITIVE_TYPE_TRIANGLES,
triangleCount * 3,
verts
);
if(ret.code != ERROR_OK) {
memoryFree(verts);
errorChain(ret);
}
ret = assetFileClose(file);
if(ret.code != ERROR_OK) {
errorCatch(errorPrint(meshDispose(output->outMesh)));
memoryFree(verts);
errorChain(ret);
}
errorOk();
}
// errorret_t assetMeshLoadToOutput(
// const char_t *path,
// assetmeshoutput_t *output
// ) {
// assertNotNull(path, "Path cannot be null");
// assertNotNull(output, "Output cannot be null");
// assertNotNull(output->outMesh, "Output mesh cannot be null");
// assertNotNull(output->outVertices, "Output vertices cannot be null");
// return assetLoad(path, &assetMeshLoader, NULL, output);
// }
// errorret_t assetMeshLoad(
// const char_t *path,
// mesh_t *outMesh,
// meshvertex_t **outVertices,
// const assetmeshinputaxis_t inputAxis
// ) {
// assertNotNull(path, "Path cannot be null");
// assertNotNull(outMesh, "Output mesh cannot be null");
// assertNotNull(outVertices, "Output vertices cannot be null");
// assetmeshoutput_t output = {
// outMesh,
// outVertices,
// inputAxis
// };
// return assetMeshLoadToOutput(path, &output);
// }