lovr/src/data/modelData_obj.c

166 lines
4.9 KiB
C
Raw Normal View History

#include "data/modelData.h"
#include "lib/math.h"
#include <stdio.h>
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO io) {
char* data = (char*) source->data;
size_t length = source->size;
vec_float_t vertexBuffer;
vec_int_t indexBuffer;
map_int_t vertexMap;
vec_float_t vertices;
vec_float_t normals;
vec_float_t uvs;
vec_init(&vertexBuffer);
vec_init(&indexBuffer);
map_init(&vertexMap);
vec_init(&vertices);
vec_init(&normals);
vec_init(&uvs);
while (length > 0) {
int lineLength = 0;
if (STARTS_WITH(data, "v ")) {
float x, y, z;
int count = sscanf(data + 2, "%f %f %f\n%n", &x, &y, &z, &lineLength);
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex position");
vec_pusharr(&vertices, ((float[3]) { x, y, z }), 3);
} else if (STARTS_WITH(data, "vn ")) {
float x, y, z;
int count = sscanf(data + 3, "%f %f %f\n%n", &x, &y, &z, &lineLength);
lovrAssert(count == 3, "Bad OBJ: Expected 3 coordinates for vertex normal");
vec_pusharr(&normals, ((float[3]) { x, y, z }), 3);
} else if (STARTS_WITH(data, "vt ")) {
float u, v;
int count = sscanf(data + 3, "%f %f\n%n", &u, &v, &lineLength);
lovrAssert(count == 2, "Bad OBJ: Expected 2 coordinates for texture coordinate");
vec_pusharr(&uvs, ((float[2]) { u, v }), 2);
} else if (STARTS_WITH(data, "f ")) {
char* s = data + 2;
for (int i = 0; i < 3; i++) {
char terminator = i == 2 ? '\n' : ' ';
char* space = strchr(s, terminator);
if (space) {
*space = '\0'; // I'll be back
int* index = map_get(&vertexMap, s);
if (index) {
vec_push(&indexBuffer, *index);
} else {
int v, vt, vn;
int newIndex = vertexBuffer.length / 8;
vec_push(&indexBuffer, newIndex);
map_set(&vertexMap, s, newIndex);
// Can be improved
if (sscanf(s, "%d/%d/%d", &v, &vt, &vn) == 3) {
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBuffer, normals.data + 3 * (vn - 1), 3);
vec_pusharr(&vertexBuffer, uvs.data + 2 * (vt - 1), 2);
} else if (sscanf(s, "%d//%d", &v, &vn) == 2) {
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBuffer, normals.data + 3 * (vn - 1), 3);
vec_pusharr(&vertexBuffer, ((float[2]) { 0 }), 2);
} else if (sscanf(s, "%d", &v) == 1) {
vec_pusharr(&vertexBuffer, vertices.data + 3 * (v - 1), 3);
vec_pusharr(&vertexBuffer, ((float[5]) { 0 }), 5);
} else {
lovrThrow("Bad OBJ: Unknown face format");
}
}
*space = terminator;
s = space + 1;
}
}
lineLength = s - data;
} else {
char* newline = memchr(data, '\n', length);
lineLength = newline - data + 1;
}
data += lineLength;
length -= lineLength;
}
model->blobCount = 2;
model->bufferCount = 2;
model->attributeCount = 4;
model->primitiveCount = 1;
model->nodeCount = 1;
lovrModelDataAllocate(model);
model->blobs[0] = lovrBlobCreate(vertexBuffer.data, vertexBuffer.length * sizeof(float), "obj vertex data");
model->blobs[1] = lovrBlobCreate(indexBuffer.data, indexBuffer.length * sizeof(int), "obj index data");
model->buffers[0] = (ModelBuffer) {
.data = model->blobs[0]->data,
.size = model->blobs[0]->size,
.stride = 8 * sizeof(float)
};
model->buffers[1] = (ModelBuffer) {
.data = model->blobs[1]->data,
.size = model->blobs[1]->size,
.stride = sizeof(int)
};
model->attributes[0] = (ModelAttribute) {
.buffer = 0,
.offset = 0,
.count = vertexBuffer.length / 8,
.type = F32,
.components = 3
};
model->attributes[1] = (ModelAttribute) {
.buffer = 0,
.offset = 3 * sizeof(float),
.count = vertexBuffer.length / 8,
.type = F32,
.components = 3
};
model->attributes[2] = (ModelAttribute) {
.buffer = 0,
.offset = 6 * sizeof(float),
.count = vertexBuffer.length / 8,
.type = F32,
.components = 2
};
model->attributes[3] = (ModelAttribute) {
.buffer = 1,
.offset = 0,
.count = indexBuffer.length,
.type = U32,
.components = 1
};
model->primitives[0] = (ModelPrimitive) {
.mode = DRAW_TRIANGLES,
.attributes = {
[ATTR_POSITION] = &model->attributes[0],
[ATTR_NORMAL] = &model->attributes[1],
[ATTR_TEXCOORD] = &model->attributes[2]
},
.indices = &model->attributes[3],
.material = -1
};
model->nodes[0] = (ModelNode) {
.transform = MAT4_IDENTITY,
.primitiveIndex = 0,
.primitiveCount = 1
};
map_deinit(&vertexMap);
vec_deinit(&vertices);
vec_deinit(&normals);
vec_deinit(&uvs);
return model;
}