From 72a54bce2f4140ef0429c43e8ce0e4008aef975e Mon Sep 17 00:00:00 2001 From: bjorn Date: Tue, 23 Feb 2021 12:07:16 -0700 Subject: [PATCH] Support STL models; Only binary STL files are supported right now, ASCII is more challenging. --- src/modules/data/modelData.c | 2 + src/modules/data/modelData.h | 1 + src/modules/data/modelData_stl.c | 76 ++++++++++++++++++++++++++++++++ src/modules/graphics/model.c | 3 +- 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/modules/data/modelData_stl.c diff --git a/src/modules/data/modelData.c b/src/modules/data/modelData.c index de69454d..32b5e230 100644 --- a/src/modules/data/modelData.c +++ b/src/modules/data/modelData.c @@ -12,6 +12,8 @@ ModelData* lovrModelDataCreate(Blob* source, ModelDataIO* io) { return model; } else if (lovrModelDataInitObj(model, source, io)) { return model; + } else if (lovrModelDataInitStl(model, source, io)) { + return model; } lovrThrow("Unable to load model from '%s'", source->name); diff --git a/src/modules/data/modelData.h b/src/modules/data/modelData.h index 89741fb1..778f0bec 100644 --- a/src/modules/data/modelData.h +++ b/src/modules/data/modelData.h @@ -221,5 +221,6 @@ typedef void* ModelDataIO(const char* filename, size_t* bytesRead); ModelData* lovrModelDataCreate(struct Blob* blob, ModelDataIO* io); ModelData* lovrModelDataInitGltf(ModelData* model, struct Blob* blob, ModelDataIO* io); ModelData* lovrModelDataInitObj(ModelData* model, struct Blob* blob, ModelDataIO* io); +ModelData* lovrModelDataInitStl(ModelData* model, struct Blob* blob, ModelDataIO* io); void lovrModelDataDestroy(void* ref); void lovrModelDataAllocate(ModelData* model); diff --git a/src/modules/data/modelData_stl.c b/src/modules/data/modelData_stl.c new file mode 100644 index 00000000..adb166bd --- /dev/null +++ b/src/modules/data/modelData_stl.c @@ -0,0 +1,76 @@ +#include "data/modelData.h" +#include "data/blob.h" +#include "core/maf.h" +#include "core/util.h" +#include +#include + +static ModelData* lovrModelDataInitStlAscii(ModelData* model, Blob* source, ModelDataIO* io) { + lovrThrow("ASCII STL files are not supported yet"); + return NULL; +} + +// The binary format has an 80 byte header, followed by a u32 triangle count, followed by 50 byte +// triangles. Each triangle has a vec3 normal, 3 vec3 vertices, and 2 bytes of padding. +extern ModelData* lovrModelDataInitStlBinary(ModelData* model, Blob* source, ModelDataIO* io, uint32_t triangleCount) { + char* data = (char*) source->data + 84; + + uint32_t vertexCount = triangleCount * 3; + size_t vertexBufferSize = vertexCount * 6 * sizeof(float); + float* vertices = malloc(vertexBufferSize); + lovrAssert(vertices, "Out of memory"); + + model->blobCount = 1; + model->bufferCount = 1; + model->attributeCount = 2; + model->primitiveCount = 1; + model->nodeCount = 1; + + lovrModelDataAllocate(model); + + model->blobs[0] = lovrBlobCreate(vertices, vertexBufferSize, "stl vertex data"); + model->buffers[0] = (ModelBuffer) { .data = (char*) vertices, .size = vertexBufferSize, .stride = 6 * sizeof(float) }; + model->attributes[0] = (ModelAttribute) { .count = vertexCount, .components = 3, .type = F32, .offset = 0 * sizeof(float) }; + model->attributes[1] = (ModelAttribute) { .count = vertexCount, .components = 3, .type = F32, .offset = 3 * sizeof(float) }; + model->primitives[0] = (ModelPrimitive) { + .mode = DRAW_TRIANGLES, + .material = ~0u, + .attributes = { + [ATTR_POSITION] = &model->attributes[0], + [ATTR_NORMAL] = &model->attributes[1] + } + }; + model->nodes[0] = (ModelNode) { + .matrix = true, + .transform.matrix = MAT4_IDENTITY, + .primitiveCount = 1, + .skin = ~0u + }; + + for (uint32_t i = 0; i < triangleCount; i++) { + memcpy(vertices + 3, data, 12); + memcpy(vertices + 9, data, 12); + memcpy(vertices + 15, data, 12), data += 12; + memcpy(vertices + 0, data, 12), data += 12; + memcpy(vertices + 6, data, 12), data += 12; + memcpy(vertices + 12, data, 12), data += 12; + vertices += 18; + data += 2; + } + + return model; +} + +ModelData* lovrModelDataInitStl(ModelData* model, Blob* source, ModelDataIO* io) { + if (source->size > strlen("solid ") && !memcmp(source->data, "solid ", strlen("solid "))) { + return lovrModelDataInitStlAscii(model, source, io); + } else if (source->size > 84) { + uint32_t triangleCount; + memcpy(&triangleCount, (char*) source->data + 80, sizeof(triangleCount)); + if (source->size == 84 + 50 * triangleCount) { + return lovrModelDataInitStlBinary(model, source, io, triangleCount); + } + } + + return NULL; +} diff --git a/src/modules/graphics/model.c b/src/modules/graphics/model.c index 1686b17f..b3764817 100644 --- a/src/modules/graphics/model.c +++ b/src/modules/graphics/model.c @@ -130,7 +130,8 @@ Model* lovrModelCreate(ModelData* data) { model->meshes = calloc(data->primitiveCount, sizeof(Mesh*)); for (uint32_t i = 0; i < data->primitiveCount; i++) { ModelPrimitive* primitive = &data->primitives[i]; - model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, 0); + uint32_t vertexCount = primitive->attributes[ATTR_POSITION] ? primitive->attributes[ATTR_POSITION]->count : 0; + model->meshes[i] = lovrMeshCreate(primitive->mode, NULL, vertexCount); if (primitive->material != ~0u) { lovrMeshSetMaterial(model->meshes[i], model->materials[primitive->material]);