2016-11-19 09:28:01 +00:00
|
|
|
#include "graphics/model.h"
|
|
|
|
#include "graphics/graphics.h"
|
2016-10-04 04:54:27 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2016-10-31 20:54:32 +00:00
|
|
|
static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) {
|
|
|
|
mat4 newTransform;
|
|
|
|
|
|
|
|
if (!transform) {
|
|
|
|
newTransform = mat4_init();
|
|
|
|
} else {
|
|
|
|
newTransform = mat4_copy(transform);
|
|
|
|
}
|
|
|
|
|
|
|
|
mat4_multiply(newTransform, node->transform);
|
|
|
|
|
|
|
|
int indexOffset = vertices->length / 3;
|
|
|
|
|
|
|
|
// Meshes
|
|
|
|
for (int m = 0; m < node->meshes.length; m++) {
|
|
|
|
ModelMesh* mesh = modelData->meshes.data[node->meshes.data[m]];
|
|
|
|
|
|
|
|
// Transformed vertices
|
|
|
|
for (int v = 0; v < mesh->vertices.length; v++) {
|
|
|
|
ModelVertex vertex = mesh->vertices.data[v];
|
|
|
|
|
2016-11-02 04:52:32 +00:00
|
|
|
float transformedVertex[4] = {
|
2016-10-31 20:54:32 +00:00
|
|
|
vertex.x,
|
|
|
|
vertex.y,
|
|
|
|
vertex.z,
|
|
|
|
1.f
|
|
|
|
};
|
|
|
|
|
2016-11-02 04:52:32 +00:00
|
|
|
mat4_multiplyVector(newTransform, transformedVertex);
|
|
|
|
vec_pusharr(vertices, transformedVertex, 3);
|
|
|
|
|
|
|
|
if (modelData->hasNormals) {
|
|
|
|
ModelVertex normal = mesh->normals.data[v];
|
|
|
|
vec_push(vertices, normal.x);
|
|
|
|
vec_push(vertices, normal.y);
|
|
|
|
vec_push(vertices, normal.z);
|
|
|
|
}
|
2016-11-23 08:02:19 +00:00
|
|
|
|
|
|
|
if (modelData->hasTexCoords) {
|
|
|
|
ModelVertex texCoord = mesh->texCoords.data[v];
|
|
|
|
vec_push(vertices, texCoord.x);
|
|
|
|
vec_push(vertices, texCoord.y);
|
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Face vertex indices
|
|
|
|
for (int f = 0; f < mesh->faces.length; f++) {
|
|
|
|
ModelFace face = mesh->faces.data[f];
|
2016-11-25 11:16:11 +00:00
|
|
|
vec_push(indices, face.indices[0] + indexOffset);
|
|
|
|
vec_push(indices, face.indices[1] + indexOffset);
|
|
|
|
vec_push(indices, face.indices[2] + indexOffset);
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int c = 0; c < node->children.length; c++) {
|
|
|
|
visitNode(modelData, node->children.data[c], newTransform, vertices, indices);
|
|
|
|
}
|
2016-11-18 10:03:50 +00:00
|
|
|
|
|
|
|
mat4_deinit(newTransform);
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
Model* lovrModelCreate(ModelData* modelData) {
|
2016-11-19 07:41:23 +00:00
|
|
|
Model* model = lovrAlloc(sizeof(Model), lovrModelDestroy);
|
2016-11-08 22:44:03 +00:00
|
|
|
if (!model) return NULL;
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
model->modelData = modelData;
|
2016-10-31 20:54:32 +00:00
|
|
|
|
|
|
|
vec_float_t vertices;
|
|
|
|
vec_init(&vertices);
|
|
|
|
|
|
|
|
vec_uint_t indices;
|
|
|
|
vec_init(&indices);
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
visitNode(modelData, modelData->root, NULL, &vertices, &indices);
|
2016-10-31 20:54:32 +00:00
|
|
|
|
|
|
|
BufferFormat format;
|
|
|
|
vec_init(&format);
|
2016-11-02 04:52:32 +00:00
|
|
|
|
2016-11-23 08:02:19 +00:00
|
|
|
int components = 3;
|
2016-11-23 06:17:40 +00:00
|
|
|
BufferAttribute position = { .name = "lovrPosition", .type = BUFFER_FLOAT, .count = 3 };
|
2016-10-31 20:54:32 +00:00
|
|
|
vec_push(&format, position);
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
if (modelData->hasNormals) {
|
2016-11-23 06:17:40 +00:00
|
|
|
BufferAttribute normal = { .name = "lovrNormal", .type = BUFFER_FLOAT, .count = 3 };
|
2016-11-02 04:52:32 +00:00
|
|
|
vec_push(&format, normal);
|
2016-11-23 08:02:19 +00:00
|
|
|
components += 3;
|
2016-11-02 04:52:32 +00:00
|
|
|
}
|
|
|
|
|
2016-11-25 08:49:19 +00:00
|
|
|
if (modelData->hasTexCoords) {
|
2016-11-25 11:14:48 +00:00
|
|
|
BufferAttribute texCoord = { .name = "lovrTexCoord", .type = BUFFER_FLOAT, .count = 2 };
|
|
|
|
vec_push(&format, texCoord);
|
2016-11-23 08:02:19 +00:00
|
|
|
components += 2;
|
|
|
|
}
|
2016-11-02 04:52:32 +00:00
|
|
|
|
|
|
|
model->buffer = lovrBufferCreate(vertices.length / components, &format, BUFFER_TRIANGLES, BUFFER_STATIC);
|
2016-11-13 07:18:53 +00:00
|
|
|
lovrBufferSetVertices(model->buffer, (void*) vertices.data, vertices.length * sizeof(float));
|
2016-10-31 20:54:32 +00:00
|
|
|
lovrBufferSetVertexMap(model->buffer, indices.data, indices.length);
|
|
|
|
|
2016-11-08 22:51:58 +00:00
|
|
|
model->texture = NULL;
|
|
|
|
|
2016-11-18 10:03:50 +00:00
|
|
|
vec_deinit(&format);
|
2016-10-31 20:54:32 +00:00
|
|
|
vec_deinit(&vertices);
|
|
|
|
vec_deinit(&indices);
|
2016-10-04 04:54:27 +00:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2016-11-19 07:41:23 +00:00
|
|
|
void lovrModelDestroy(const Ref* ref) {
|
|
|
|
Model* model = containerof(ref, Model);
|
2016-11-23 08:02:19 +00:00
|
|
|
if (model->texture) {
|
|
|
|
lovrRelease(&model->texture->ref);
|
|
|
|
}
|
2016-11-26 07:15:04 +00:00
|
|
|
lovrModelDataDestroy(model->modelData);
|
2016-11-19 07:41:23 +00:00
|
|
|
lovrRelease(&model->buffer->ref);
|
2016-10-04 04:54:27 +00:00
|
|
|
free(model);
|
|
|
|
}
|
2016-10-31 20:54:32 +00:00
|
|
|
|
2016-11-26 07:15:04 +00:00
|
|
|
void lovrModelDataDestroy(ModelData* modelData) {
|
|
|
|
for (int i = 0; i < modelData->meshes.length; i++) {
|
|
|
|
ModelMesh* mesh = modelData->meshes.data[i];
|
|
|
|
vec_deinit(&mesh->faces);
|
|
|
|
vec_deinit(&mesh->vertices);
|
|
|
|
vec_deinit(&mesh->normals);
|
|
|
|
if (modelData->hasTexCoords) {
|
|
|
|
vec_deinit(&mesh->texCoords);
|
|
|
|
}
|
|
|
|
free(mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec_void_t nodes;
|
|
|
|
vec_init(&nodes);
|
|
|
|
vec_push(&nodes, modelData->root);
|
|
|
|
while (nodes.length > 0) {
|
|
|
|
ModelNode* node = vec_first(&nodes);
|
|
|
|
vec_extend(&nodes, &node->children);
|
|
|
|
mat4_deinit(node->transform);
|
|
|
|
vec_deinit(&node->meshes);
|
|
|
|
vec_deinit(&node->children);
|
|
|
|
vec_splice(&nodes, 0, 1);
|
|
|
|
free(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec_deinit(&modelData->meshes);
|
|
|
|
vec_deinit(&nodes);
|
|
|
|
free(modelData);
|
|
|
|
}
|
|
|
|
|
2016-11-02 03:56:29 +00:00
|
|
|
void lovrModelDraw(Model* model, float x, float y, float z, float size, float angle, float ax, float ay, float az) {
|
|
|
|
lovrGraphicsPush();
|
|
|
|
lovrGraphicsTransform(x, y, z, size, size, size, angle, ax, ay, az);
|
2016-10-31 20:54:32 +00:00
|
|
|
lovrBufferDraw(model->buffer);
|
2016-11-02 03:56:29 +00:00
|
|
|
lovrGraphicsPop();
|
2016-10-31 20:54:32 +00:00
|
|
|
}
|
2016-11-08 22:51:58 +00:00
|
|
|
|
|
|
|
Texture* lovrModelGetTexture(Model* model) {
|
|
|
|
return model->texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lovrModelSetTexture(Model* model, Texture* texture) {
|
2016-11-23 08:02:19 +00:00
|
|
|
if (model->texture) {
|
|
|
|
lovrRelease(&model->texture->ref);
|
|
|
|
}
|
|
|
|
|
2016-11-08 22:51:58 +00:00
|
|
|
model->texture = texture;
|
2016-11-23 08:02:19 +00:00
|
|
|
lovrBufferSetTexture(model->buffer, model->texture);
|
|
|
|
|
|
|
|
if (model->texture) {
|
|
|
|
lovrRetain(&model->texture->ref);
|
|
|
|
}
|
2016-11-08 22:51:58 +00:00
|
|
|
}
|