Support STL models;

Only binary STL files are supported right now, ASCII is more challenging.
This commit is contained in:
bjorn 2021-02-23 12:07:16 -07:00
parent a430ae06b8
commit 72a54bce2f
4 changed files with 81 additions and 1 deletions

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,76 @@
#include "data/modelData.h"
#include "data/blob.h"
#include "core/maf.h"
#include "core/util.h"
#include <stdlib.h>
#include <string.h>
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;
}

View File

@ -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]);