diff --git a/src/api/types/model.c b/src/api/types/model.c index 57e9d38d..3444ae9f 100644 --- a/src/api/types/model.c +++ b/src/api/types/model.c @@ -23,19 +23,9 @@ int l_lovrModelSetTexture(lua_State* L) { return 0; } -int l_lovrModelGetAABB(lua_State* L) { - Model* model = luax_checktype(L, 1, Model); - float* aabb = lovrModelGetAABB(model); - for (int i = 0; i < 6; i++) { - lua_pushnumber(L, aabb[i]); - } - return 6; -} - const luaL_Reg lovrModel[] = { { "draw", l_lovrModelDraw }, { "getTexture", l_lovrModelGetTexture }, { "setTexture", l_lovrModelSetTexture }, - { "getAABB", l_lovrModelGetAABB }, { NULL, NULL } }; diff --git a/src/graphics/mesh.c b/src/graphics/mesh.c index 72ff7bce..185c59e6 100644 --- a/src/graphics/mesh.c +++ b/src/graphics/mesh.c @@ -119,8 +119,11 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) { lovrMeshUnmap(mesh); } - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); + if (transform) { + lovrGraphicsPush(); + lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); + } + lovrGraphicsBindTexture(mesh->texture); lovrGraphicsSetDefaultShader(SHADER_DEFAULT); lovrGraphicsPrepare(); @@ -129,11 +132,15 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform) { size_t start = mesh->rangeStart; size_t count = mesh->rangeCount; if (mesh->map.length > 0) { - glDrawElements(mesh->drawMode, mesh->map.length, GL_UNSIGNED_INT, (GLvoid*) start); + count = mesh->isRangeEnabled ? mesh->rangeCount : mesh->map.length; + glDrawElements(mesh->drawMode, count, GL_UNSIGNED_INT, (GLvoid*) (start * sizeof(unsigned int))); } else { glDrawArrays(mesh->drawMode, start, count); } - lovrGraphicsPop(); + + if (transform) { + lovrGraphicsPop(); + } } MeshFormat lovrMeshGetVertexFormat(Mesh* mesh) { @@ -224,7 +231,9 @@ void lovrMeshGetDrawRange(Mesh* mesh, int* start, int* count) { } int lovrMeshSetDrawRange(Mesh* mesh, int start, int count) { - if (start < 0 || count < 0 || (size_t) start + count > mesh->count) { + size_t limit = mesh->map.length > 0 ? mesh->map.length : mesh->count; + + if (start < 0 || count < 0 || (size_t) start + count > limit) { return 1; } diff --git a/src/graphics/model.c b/src/graphics/model.c index 2b0a3d70..f1cb4b35 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -3,66 +3,24 @@ #include "math/mat4.h" #include "math/vec3.h" #include -#include -static void visitNode(Model* model, ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) { - float newTransform[16]; +static void renderNode(Model* model, int nodeIndex) { + ModelNode* node = &model->modelData->nodes[nodeIndex]; - if (transform) { - mat4_set(newTransform, transform); - } else { - mat4_identity(newTransform); + lovrGraphicsPush(); + lovrGraphicsMatrixTransform(MATRIX_MODEL, node->transform); + + for (int i = 0; i < node->primitives.length; i++) { + ModelPrimitive* primitive = &model->modelData->primitives[node->primitives.data[i]]; + lovrMeshSetDrawRange(model->mesh, primitive->drawStart, primitive->drawCount); + lovrMeshDraw(model->mesh, NULL); } - 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]; - - float vec[3] = { vertex.x, vertex.y, vertex.z }; - mat4_transform(newTransform, vec); - vec_pusharr(vertices, vec, 3); - - model->aabb[0] = MIN(model->aabb[0], vec[0]); - model->aabb[1] = MAX(model->aabb[1], vec[0]); - model->aabb[2] = MIN(model->aabb[2], vec[1]); - model->aabb[3] = MAX(model->aabb[3], vec[1]); - model->aabb[4] = MIN(model->aabb[4], vec[2]); - model->aabb[5] = MAX(model->aabb[5], vec[2]); - - if (modelData->hasNormals) { - ModelVertex normal = mesh->normals.data[v]; - vec_push(vertices, normal.x); - vec_push(vertices, normal.y); - vec_push(vertices, normal.z); - } - - if (modelData->hasTexCoords) { - ModelVertex texCoord = mesh->texCoords.data[v]; - vec_push(vertices, texCoord.x); - vec_push(vertices, texCoord.y); - } - } - - // Face vertex indices - for (int f = 0; f < mesh->faces.length; f++) { - ModelFace face = mesh->faces.data[f]; - vec_push(indices, face.indices[0] + indexOffset); - vec_push(indices, face.indices[1] + indexOffset); - vec_push(indices, face.indices[2] + indexOffset); - } + for (int i = 0; i < node->children.length; i++) { + renderNode(model, node->children.data[i]); } - for (int c = 0; c < node->children.length; c++) { - visitNode(model, modelData, node->children.data[c], newTransform, vertices, indices); - } + lovrGraphicsPop(); } Model* lovrModelCreate(ModelData* modelData) { @@ -70,51 +28,33 @@ Model* lovrModelCreate(ModelData* modelData) { if (!model) return NULL; model->modelData = modelData; - model->aabb[0] = FLT_MAX; - model->aabb[1] = FLT_MIN; - model->aabb[2] = FLT_MAX; - model->aabb[3] = FLT_MIN; - model->aabb[4] = FLT_MAX; - model->aabb[5] = FLT_MIN; - - vec_float_t vertices; - vec_init(&vertices); - - vec_uint_t indices; - vec_init(&indices); - - visitNode(model, modelData, modelData->root, NULL, &vertices, &indices); MeshFormat format; vec_init(&format); - int components = 3; - MeshAttribute position = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 }; - vec_push(&format, position); + MeshAttribute attribute = { .name = "lovrPosition", .type = MESH_FLOAT, .count = 3 }; + vec_push(&format, attribute); if (modelData->hasNormals) { - MeshAttribute normal = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 }; - vec_push(&format, normal); - components += 3; + MeshAttribute attribute = { .name = "lovrNormal", .type = MESH_FLOAT, .count = 3 }; + vec_push(&format, attribute); } - if (modelData->hasTexCoords) { - MeshAttribute texCoord = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 }; - vec_push(&format, texCoord); - components += 2; + if (modelData->hasUVs) { + MeshAttribute attribute = { .name = "lovrTexCoord", .type = MESH_FLOAT, .count = 2 }; + vec_push(&format, attribute); } - model->mesh = lovrMeshCreate(vertices.length / components, &format, MESH_TRIANGLES, MESH_STATIC); - void* data = lovrMeshMap(model->mesh, 0, vertices.length / components, 0, 1); - memcpy(data, vertices.data, vertices.length * sizeof(float)); + model->mesh = lovrMeshCreate(modelData->vertexCount, &format, MESH_TRIANGLES, MESH_STATIC); + void* data = lovrMeshMap(model->mesh, 0, modelData->vertexCount, 0, 1); + memcpy(data, modelData->vertices, modelData->vertexCount * modelData->vertexSize * sizeof(float)); lovrMeshUnmap(model->mesh); - lovrMeshSetVertexMap(model->mesh, indices.data, indices.length); + lovrMeshSetVertexMap(model->mesh, modelData->indices, modelData->indexCount); + lovrMeshSetRangeEnabled(model->mesh, 1); model->texture = NULL; vec_deinit(&format); - vec_deinit(&vertices); - vec_deinit(&indices); return model; } @@ -129,7 +69,14 @@ void lovrModelDestroy(const Ref* ref) { } void lovrModelDraw(Model* model, mat4 transform) { - lovrMeshDraw(model->mesh, transform); + if (model->modelData->nodeCount == 0) { + return; + } + + lovrGraphicsPush(); + lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); + renderNode(model, 0); + lovrGraphicsPop(); } Texture* lovrModelGetTexture(Model* model) { @@ -148,7 +95,3 @@ void lovrModelSetTexture(Model* model, Texture* texture) { lovrRetain(&model->texture->ref); } } - -float* lovrModelGetAABB(Model* model) { - return model->aabb; -} diff --git a/src/graphics/model.h b/src/graphics/model.h index dc11e223..d5719f79 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -12,7 +12,6 @@ typedef struct { ModelData* modelData; Mesh* mesh; Texture* texture; - float aabb[6]; } Model; Model* lovrModelCreate(ModelData* modelData); @@ -20,4 +19,3 @@ void lovrModelDestroy(const Ref* ref); void lovrModelDraw(Model* model, mat4 transform); Texture* lovrModelGetTexture(Model* model); void lovrModelSetTexture(Model* model, Texture* texture); -float* lovrModelGetAABB(Model* model); diff --git a/src/headset/openvr.c b/src/headset/openvr.c index 2f4aa98f..e004cee5 100644 --- a/src/headset/openvr.c +++ b/src/headset/openvr.c @@ -600,53 +600,49 @@ ModelData* lovrHeadsetControllerNewModelData(Controller* controller) { ModelData* modelData = malloc(sizeof(ModelData)); if (!modelData) return NULL; - ModelMesh* mesh = malloc(sizeof(ModelMesh)); - vec_init(&modelData->meshes); - vec_push(&modelData->meshes, mesh); + modelData->indexCount = vrModel->unTriangleCount; + modelData->indices = malloc(modelData->indexCount * sizeof(unsigned int)); + memcpy(modelData->indices, vrModel->rIndexData, modelData->indexCount * sizeof(unsigned int)); - vec_init(&mesh->faces); - for (uint32_t i = 0; i < vrModel->unTriangleCount; i++) { - ModelFace face; - face.indices[0] = vrModel->rIndexData[3 * i + 0]; - face.indices[1] = vrModel->rIndexData[3 * i + 1]; - face.indices[2] = vrModel->rIndexData[3 * i + 2]; - vec_push(&mesh->faces, face); - } + modelData->vertexCount = vrModel->unVertexCount; + modelData->vertexSize = 8; + modelData->vertices = malloc(modelData->vertexCount * modelData->vertexSize * sizeof(float)); - vec_init(&mesh->vertices); - vec_init(&mesh->normals); - vec_init(&mesh->texCoords); + int vertex = 0; for (size_t i = 0; i < vrModel->unVertexCount; i++) { float* position = vrModel->rVertexData[i].vPosition.v; float* normal = vrModel->rVertexData[i].vNormal.v; float* texCoords = vrModel->rVertexData[i].rfTextureCoord; - ModelVertex v; - v.x = position[0]; - v.y = position[1]; - v.z = position[2]; - vec_push(&mesh->vertices, v); + modelData->vertices[vertex++] = position[0]; + modelData->vertices[vertex++] = position[1]; + modelData->vertices[vertex++] = position[2]; - v.x = normal[0]; - v.y = normal[1]; - v.z = normal[2]; - vec_push(&mesh->normals, v); + modelData->vertices[vertex++] = normal[0]; + modelData->vertices[vertex++] = normal[1]; + modelData->vertices[vertex++] = normal[2]; - v.x = texCoords[0]; - v.y = texCoords[1]; - v.z = 0.f; - vec_push(&mesh->texCoords, v); + modelData->vertices[vertex++] = texCoords[0]; + modelData->vertices[vertex++] = texCoords[1]; } - ModelNode* root = malloc(sizeof(ModelNode)); - vec_init(&root->meshes); - vec_push(&root->meshes, 0); - vec_init(&root->children); - mat4_identity(root->transform); + modelData->nodeCount = 1; + modelData->primitiveCount = 1; + + modelData->nodes = malloc(1 * sizeof(ModelNode)); + modelData->primitives = malloc(1 * sizeof(ModelPrimitive)); + + ModelNode* root = &modelData->nodes[0]; + root->parent = -1; + mat4_identity(root->transform); + vec_init(&root->children); + vec_init(&root->primitives); + vec_push(&root->primitives, 0); + modelData->primitives[0].drawStart = 0; + modelData->primitives[0].drawCount = modelData->vertexCount; - modelData->root = root; modelData->hasNormals = 1; - modelData->hasTexCoords = 1; + modelData->hasUVs = 1; return modelData; } diff --git a/src/loaders/model.c b/src/loaders/model.c index b59c4ec2..707bcb7f 100644 --- a/src/loaders/model.c +++ b/src/loaders/model.c @@ -2,29 +2,41 @@ #include "math/mat4.h" #include #include +#include #include #include #include #include #include -static void assimpNodeTraversal(ModelNode* node, struct aiNode* assimpNode) { +static void assimpSumChildren(struct aiNode* assimpNode, int* totalChildren) { + (*totalChildren)++; + for (unsigned int i = 0; i < assimpNode->mNumChildren; i++) { + assimpSumChildren(assimpNode->mChildren[i], totalChildren); + } +} + +static void assimpNodeTraversal(ModelData* modelData, struct aiNode* assimpNode, int* nodeId) { + int currentIndex = *nodeId; + ModelNode* node = &modelData->nodes[currentIndex]; // Transform struct aiMatrix4x4 m = assimpNode->mTransformation; aiTransposeMatrix4(&m); mat4_set(node->transform, (float*) &m); - // Meshes - vec_init(&node->meshes); - vec_pusharr(&node->meshes, assimpNode->mMeshes, assimpNode->mNumMeshes); + // Primitives + vec_init(&node->primitives); + vec_pusharr(&node->primitives, assimpNode->mMeshes, assimpNode->mNumMeshes); // Children vec_init(&node->children); for (unsigned int n = 0; n < assimpNode->mNumChildren; n++) { - ModelNode* child = malloc(sizeof(ModelNode)); - assimpNodeTraversal(child, assimpNode->mChildren[n]); - vec_push(&node->children, child); + (*nodeId)++; + vec_push(&node->children, *nodeId); + ModelNode* child = &modelData->nodes[*nodeId]; + child->parent = currentIndex; + assimpNodeTraversal(modelData, assimpNode->mChildren[n], nodeId); } } @@ -32,104 +44,104 @@ ModelData* lovrModelDataCreate(Blob* blob) { ModelData* modelData = malloc(sizeof(ModelData)); if (!modelData) return NULL; - modelData->hasNormals = 0; - modelData->hasTexCoords = 0; - + struct aiPropertyStore* propertyStore = aiCreatePropertyStore(); + aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE); unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_FlipUVs; - const struct aiScene* scene = aiImportFileFromMemory(blob->data, blob->size, flags, NULL); + const struct aiScene* scene = aiImportFileFromMemoryWithProperties(blob->data, blob->size, flags, NULL, propertyStore); + aiReleasePropertyStore(propertyStore); + + modelData->nodeCount = 0; + modelData->vertexCount = 0; + modelData->indexCount = 0; + modelData->hasNormals = 0; + modelData->hasUVs = 0; - // Meshes - vec_init(&modelData->meshes); for (unsigned int m = 0; m < scene->mNumMeshes; m++) { struct aiMesh* assimpMesh = scene->mMeshes[m]; - ModelMesh* mesh = malloc(sizeof(ModelMesh)); - vec_push(&modelData->meshes, mesh); + modelData->vertexCount += assimpMesh->mNumVertices; + modelData->indexCount += assimpMesh->mNumFaces * 3; + modelData->hasNormals |= assimpMesh->mNormals != NULL; + modelData->hasUVs |= assimpMesh->mTextureCoords[0] != NULL; + } - // Faces - vec_init(&mesh->faces); + // Allocate + modelData->primitiveCount = scene->mNumMeshes; + modelData->primitives = malloc(modelData->primitiveCount * sizeof(ModelPrimitive)); + modelData->vertexSize = 3 + (modelData->hasNormals ? 3 : 0) + (modelData->hasUVs ? 2 : 0); + modelData->vertices = malloc(modelData->vertexSize * modelData->vertexCount * sizeof(float)); + modelData->indices = malloc(modelData->indexCount * sizeof(uint32_t)); + + // Load + int vertex = 0; + int index = 0; + for (unsigned int m = 0; m < scene->mNumMeshes; m++) { + struct aiMesh* assimpMesh = scene->mMeshes[m]; + modelData->primitives[m].drawStart = index; + modelData->primitives[m].drawCount = 0; + + // Indices for (unsigned int f = 0; f < assimpMesh->mNumFaces; f++) { struct aiFace assimpFace = assimpMesh->mFaces[f]; + lovrAssert(assimpFace.mNumIndices == 3, "Only triangular faces are supported"); - // Skip lines and points, polygons are triangulated - if (assimpFace.mNumIndices != 3) { - continue; - } + modelData->primitives[m].drawCount += assimpFace.mNumIndices; - ModelFace face; for (unsigned int i = 0; i < assimpFace.mNumIndices; i++) { - face.indices[i] = assimpFace.mIndices[i]; + modelData->indices[index++] = (vertex / modelData->vertexSize) + assimpFace.mIndices[i]; } - vec_push(&mesh->faces, face); } // Vertices - vec_init(&mesh->vertices); for (unsigned int v = 0; v < assimpMesh->mNumVertices; v++) { - ModelVertex vertex; - vertex.x = assimpMesh->mVertices[v].x; - vertex.y = assimpMesh->mVertices[v].y; - vertex.z = assimpMesh->mVertices[v].z; - vec_push(&mesh->vertices, vertex); - } + modelData->vertices[vertex++] = assimpMesh->mVertices[v].x; + modelData->vertices[vertex++] = assimpMesh->mVertices[v].y; + modelData->vertices[vertex++] = assimpMesh->mVertices[v].z; - // Normals - lovrAssert(assimpMesh->mNormals, "Model must have normals"); + if (modelData->hasNormals) { + if (assimpMesh->mNormals) { + modelData->vertices[vertex++] = assimpMesh->mNormals[v].x; + modelData->vertices[vertex++] = assimpMesh->mNormals[v].y; + modelData->vertices[vertex++] = assimpMesh->mNormals[v].z; + } else { + modelData->vertices[vertex++] = 0; + modelData->vertices[vertex++] = 0; + modelData->vertices[vertex++] = 0; + } + } - modelData->hasNormals = 1; - vec_init(&mesh->normals); - for (unsigned int n = 0; n < assimpMesh->mNumVertices; n++) { - ModelVertex normal; - normal.x = assimpMesh->mNormals[n].x; - normal.y = assimpMesh->mNormals[n].y; - normal.z = assimpMesh->mNormals[n].z; - vec_push(&mesh->normals, normal); - } - - modelData->hasTexCoords = modelData->hasTexCoords || assimpMesh->mTextureCoords[0] != NULL; - if (assimpMesh->mTextureCoords[0]) { - vec_init(&mesh->texCoords); - for (unsigned int i = 0; i < assimpMesh->mNumVertices; i++) { - ModelVertex texCoord; - texCoord.x = assimpMesh->mTextureCoords[0][i].x; - texCoord.y = assimpMesh->mTextureCoords[0][i].y; - vec_push(&mesh->texCoords, texCoord); + if (modelData->hasUVs) { + if (assimpMesh->mTextureCoords[0]) { + modelData->vertices[vertex++] = assimpMesh->mTextureCoords[0][v].x; + modelData->vertices[vertex++] = assimpMesh->mTextureCoords[0][v].y; + } else { + modelData->vertices[vertex++] = 0; + modelData->vertices[vertex++] = 0; + } } } } // Nodes - modelData->root = malloc(sizeof(ModelNode)); - assimpNodeTraversal(modelData->root, scene->mRootNode); + modelData->nodeCount = 0; + assimpSumChildren(scene->mRootNode, &modelData->nodeCount); + modelData->nodes = malloc(modelData->nodeCount * sizeof(ModelNode)); + modelData->nodes[0].parent = -1; + int nodeIndex = 0; + assimpNodeTraversal(modelData, scene->mRootNode, &nodeIndex); aiReleaseImport(scene); return modelData; } 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); +for (int i = 0; i < modelData->nodeCount; i++) { + vec_deinit(&modelData->nodes[i].children); + vec_deinit(&modelData->nodes[i].primitives); } - 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); - vec_deinit(&node->meshes); - vec_deinit(&node->children); - vec_splice(&nodes, 0, 1); - free(node); - } - - vec_deinit(&modelData->meshes); - vec_deinit(&nodes); + free(modelData->nodes); + free(modelData->primitives); + free(modelData->vertices); + free(modelData->indices); free(modelData); } diff --git a/src/loaders/model.h b/src/loaders/model.h index 33d359ef..9b838ca1 100644 --- a/src/loaders/model.h +++ b/src/loaders/model.h @@ -5,39 +5,29 @@ #pragma once typedef struct { - float x; - float y; - float z; -} ModelVertex; + int drawStart; + int drawCount; +} ModelPrimitive; -typedef vec_t(ModelVertex) vec_model_vertex_t; - -typedef struct { - unsigned int indices[3]; -} ModelFace; - -typedef vec_t(ModelFace) vec_model_face_t; - -typedef struct { - vec_model_face_t faces; - vec_model_vertex_t vertices; - vec_model_vertex_t normals; - vec_model_vertex_t texCoords; -} ModelMesh; - -typedef vec_t(ModelMesh*) vec_model_mesh_t; - -typedef struct { +typedef struct ModelNode { float transform[16]; - vec_uint_t meshes; - vec_void_t children; + int parent; + vec_uint_t children; + vec_uint_t primitives; } ModelNode; typedef struct { - ModelNode* root; - vec_model_mesh_t meshes; + ModelNode* nodes; + ModelPrimitive* primitives; + float* vertices; + uint32_t* indices; + int nodeCount; + int primitiveCount; + int vertexCount; + int vertexSize; + int indexCount; int hasNormals; - int hasTexCoords; + int hasUVs; } ModelData; ModelData* lovrModelDataCreate(Blob* blob);