STL Loader
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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 "assert/assert.h"
|
||||
#include "util/endian.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
errorret_t assetMeshLoader(assetfile_t *file) {
|
||||
assertNotNull(file, "Asset file cannot be null");
|
||||
|
||||
assetmeshoutput_t *output = (assetmeshoutput_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++) {
|
||||
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;
|
||||
|
||||
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]
|
||||
);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 assetMeshLoad(
|
||||
const char_t *path,
|
||||
mesh_t *outMesh,
|
||||
meshvertex_t **outVertices
|
||||
) {
|
||||
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 };
|
||||
return assetLoad(path, &assetMeshLoader, NULL, &output);
|
||||
}
|
||||
Reference in New Issue
Block a user