diff --git a/CMakeLists.txt b/CMakeLists.txt index 31b21f75..2eb7ea8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,6 @@ set(LOVR_SRC src/audio/source.c src/data/audioStream.c src/data/data.c - src/data/material.c src/data/model.c src/data/rasterizer.c src/data/texture.c diff --git a/src/api/graphics.c b/src/api/graphics.c index 36db6aae..f4fb6f9d 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -5,7 +5,6 @@ #include "graphics/material.h" #include "graphics/mesh.h" #include "graphics/model.h" -#include "data/material.h" #include "data/model.h" #include "data/rasterizer.h" #include "data/texture.h" @@ -877,8 +876,7 @@ int l_lovrGraphicsNewFont(lua_State* L) { } int l_lovrGraphicsNewMaterial(lua_State* L) { - MaterialData* materialData = lovrMaterialDataCreateEmpty(); - Material* material = lovrMaterialCreate(materialData, false); + Material* material = lovrMaterialCreate(false); int index = 1; @@ -989,8 +987,7 @@ int l_lovrGraphicsNewModel(lua_State* L) { Blob* blob = luax_readblob(L, 2, "Texture"); TextureData* textureData = lovrTextureDataFromBlob(blob); Texture* texture = lovrTextureCreate(TEXTURE_2D, &textureData, 1, true); - MaterialData* materialData = lovrMaterialDataCreateEmpty(); - Material* material = lovrMaterialCreate(materialData, false); + Material* material = lovrMaterialCreate(false); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); lovrModelSetMaterial(model, material); lovrRelease(&blob->ref); diff --git a/src/data/material.c b/src/data/material.c deleted file mode 100644 index 717afaf3..00000000 --- a/src/data/material.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "data/material.h" - -MaterialData* lovrMaterialDataCreateEmpty() { - MaterialData* materialData = malloc(sizeof(MaterialData)); - - for (int i = 0; i < MAX_MATERIAL_COLORS; i++) { - materialData->colors[i] = (Color) { 1., 1., 1., 1. }; - } - - for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) { - materialData->textures[i] = NULL; - } - - return materialData; -} - -void lovrMaterialDataDestroy(MaterialData* materialData) { - free(materialData); -} diff --git a/src/data/material.h b/src/data/material.h deleted file mode 100644 index c128842a..00000000 --- a/src/data/material.h +++ /dev/null @@ -1,22 +0,0 @@ -#include "data/texture.h" - -#pragma once - -typedef enum { - COLOR_DIFFUSE, - MAX_MATERIAL_COLORS -} MaterialColor; - -typedef enum { - TEXTURE_DIFFUSE, - TEXTURE_ENVIRONMENT_MAP, - MAX_MATERIAL_TEXTURES -} MaterialTexture; - -typedef struct { - Color colors[MAX_MATERIAL_COLORS]; - TextureData* textures[MAX_MATERIAL_TEXTURES]; -} MaterialData; - -MaterialData* lovrMaterialDataCreateEmpty(); -void lovrMaterialDataDestroy(MaterialData* materialData); diff --git a/src/data/model.c b/src/data/model.c index 51c6c218..9263ca25 100644 --- a/src/data/model.c +++ b/src/data/model.c @@ -1,4 +1,5 @@ #include "data/model.h" +#include "data/texture.h" #include "filesystem/filesystem.h" #include "filesystem/file.h" #include "math/math.h" @@ -18,39 +19,6 @@ #include #include -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]; - node->name = strdup(assimpNode->mName.data); - map_set(&modelData->nodeMap, node->name, currentIndex); - - // Transform - struct aiMatrix4x4 m = assimpNode->mTransformation; - aiTransposeMatrix4(&m); - mat4_set(node->transform, (float*) &m); - - // 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++) { - (*nodeId)++; - vec_push(&node->children, *nodeId); - ModelNode* child = &modelData->nodes[*nodeId]; - child->parent = currentIndex; - assimpNodeTraversal(modelData, assimpNode->mChildren[n], nodeId); - } -} - static void normalizePath(char* path, char* dst, size_t size) { char* slash = path; while ((slash = strchr(path, '\\')) != NULL) { *slash++ = '/'; } @@ -87,6 +55,91 @@ static void normalizePath(char* path, char* dst, size_t size) { *--dst = '\0'; } +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]; + node->name = strdup(assimpNode->mName.data); + map_set(&modelData->nodeMap, node->name, currentIndex); + + // Transform + struct aiMatrix4x4 m = assimpNode->mTransformation; + aiTransposeMatrix4(&m); + mat4_set(node->transform, (float*) &m); + + // 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++) { + (*nodeId)++; + vec_push(&node->children, *nodeId); + ModelNode* child = &modelData->nodes[*nodeId]; + child->parent = currentIndex; + assimpNodeTraversal(modelData, assimpNode->mChildren[n], nodeId); + } +} + +static Color readMaterialColor(struct aiMaterial* assimpMaterial, const char* key, unsigned int type, unsigned int index) { + struct aiColor4D assimpColor; + if (aiGetMaterialColor(assimpMaterial, key, type, index, &assimpColor) == aiReturn_SUCCESS) { + Color color; + color.r = assimpColor.r; + color.g = assimpColor.g; + color.b = assimpColor.b; + color.a = assimpColor.a; + return color; + } else { + return (Color) { 1, 1, 1, 1 }; + } +} + +static int readMaterialTexture(struct aiMaterial* assimpMaterial, enum aiTextureType type, ModelData* modelData, map_int_t* textureCache, const char* dirname) { + struct aiString str; + if (aiGetMaterialTexture(assimpMaterial, type, 0, &str, NULL, NULL, NULL, NULL, NULL, NULL) == aiReturn_SUCCESS) { + char* path = str.data; + + int* cachedTexture = map_get(textureCache, path); + if (cachedTexture) { + return *cachedTexture; + } + + int textureIndex = modelData->textures.length; + + char fullPath[LOVR_PATH_MAX]; + char normalizedPath[LOVR_PATH_MAX]; + strncpy(fullPath, dirname, LOVR_PATH_MAX); + char* lastSlash = strrchr(fullPath, '/'); + if (lastSlash) lastSlash[1] = '\0'; + strncat(fullPath, path, LOVR_PATH_MAX); + normalizePath(fullPath, normalizedPath, LOVR_PATH_MAX); + + size_t size; + void* data = lovrFilesystemRead(normalizedPath, &size); + if (data) { + Blob* blob = lovrBlobCreate(data, size, path); + vec_push(&modelData->textures, lovrTextureDataFromBlob(blob)); + } else { + vec_push(&modelData->textures, NULL); + } + + map_set(textureCache, path, textureIndex); + return textureIndex; + } else { + int textureIndex = modelData->textures.length; + vec_push(&modelData->textures, NULL); + return textureIndex; + } +} + // Blob IO (to avoid reading data twice) static size_t assimpBlobRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) { Blob* blob = (Blob*) assimpFile->UserData; @@ -349,41 +402,19 @@ ModelData* lovrModelDataCreate(Blob* blob) { } // Materials + map_int_t textureCache; + map_init(&textureCache); + vec_init(&modelData->textures); modelData->materialCount = scene->mNumMaterials; - modelData->materials = malloc(modelData->materialCount * sizeof(MaterialData*)); + modelData->materials = malloc(modelData->materialCount * sizeof(ModelMaterial)); for (unsigned int m = 0; m < scene->mNumMaterials; m++) { - MaterialData* materialData = lovrMaterialDataCreateEmpty(); - struct aiMaterial* material = scene->mMaterials[m]; - struct aiColor4D color; - struct aiString str; + ModelMaterial* material = &modelData->materials[m]; + struct aiMaterial* assimpMaterial = scene->mMaterials[m]; - if (aiGetMaterialColor(material, AI_MATKEY_COLOR_DIFFUSE, &color) == aiReturn_SUCCESS) { - materialData->colors[COLOR_DIFFUSE].r = color.r; - materialData->colors[COLOR_DIFFUSE].g = color.g; - materialData->colors[COLOR_DIFFUSE].b = color.b; - materialData->colors[COLOR_DIFFUSE].a = color.a; - } - - if (aiGetMaterialTexture(material, aiTextureType_DIFFUSE, 0, &str, NULL, NULL, NULL, NULL, NULL, NULL) == aiReturn_SUCCESS) { - char* path = str.data; - char fullPath[LOVR_PATH_MAX]; - char normalizedPath[LOVR_PATH_MAX]; - strncpy(fullPath, blob->name, LOVR_PATH_MAX); - char* lastSlash = strrchr(fullPath, '/'); - if (lastSlash) lastSlash[1] = '\0'; - strncat(fullPath, path, LOVR_PATH_MAX); - normalizePath(fullPath, normalizedPath, LOVR_PATH_MAX); - - size_t size; - void* data = lovrFilesystemRead(normalizedPath, &size); - if (data) { - Blob* blob = lovrBlobCreate(data, size, path); - materialData->textures[TEXTURE_DIFFUSE] = lovrTextureDataFromBlob(blob); - } - } - - modelData->materials[m] = materialData; + material->diffuseColor = readMaterialColor(assimpMaterial, AI_MATKEY_COLOR_DIFFUSE); + material->diffuseTexture = readMaterialTexture(assimpMaterial, aiTextureType_DIFFUSE, modelData, &textureCache, blob->name); } + map_deinit(&textureCache); // Nodes modelData->nodeCount = 0; @@ -476,10 +507,12 @@ void lovrModelDataDestroy(const Ref* ref) { map_deinit(&animation->channels); } - for (int i = 0; i < modelData->materialCount; i++) { - lovrMaterialDataDestroy(modelData->materials[i]); + for (int i = 0; i < modelData->textures.length; i++) { + TextureData* textureData = modelData->textures.data[i]; + lovrRelease(&textureData->ref); } + vec_deinit(&modelData->textures); map_deinit(&modelData->nodeMap); free(modelData->nodes); diff --git a/src/data/model.h b/src/data/model.h index 390a1e3f..9f287634 100644 --- a/src/data/model.h +++ b/src/data/model.h @@ -1,5 +1,4 @@ #include "filesystem/blob.h" -#include "data/material.h" #include "util.h" #include "lib/vertex.h" #include "lib/map/map.h" @@ -66,7 +65,8 @@ typedef struct { map_int_t nodeMap; ModelPrimitive* primitives; Animation* animations; - MaterialData** materials; + ModelMaterial* materials; + vec_void_t textures; VertexFormat format; VertexData vertices; IndexData indices; diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 48fd67ac..f122276a 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -1169,8 +1169,7 @@ void lovrGraphicsBindTexture(Texture* texture, TextureType type, int slot) { Material* lovrGraphicsGetDefaultMaterial() { if (!state.defaultMaterial) { - MaterialData* materialData = lovrMaterialDataCreateEmpty(); - state.defaultMaterial = lovrMaterialCreate(materialData, true); + state.defaultMaterial = lovrMaterialCreate(true); } return state.defaultMaterial; diff --git a/src/graphics/material.c b/src/graphics/material.c index 284c6008..9ee9530f 100644 --- a/src/graphics/material.c +++ b/src/graphics/material.c @@ -1,19 +1,18 @@ #include "graphics/graphics.h" #include "graphics/material.h" -Material* lovrMaterialCreate(MaterialData* materialData, bool isDefault) { +Material* lovrMaterialCreate(bool isDefault) { Material* material = lovrAlloc(sizeof(Material), lovrMaterialDestroy); if (!material) return NULL; - material->materialData = materialData; material->isDefault = isDefault; + for (int i = 0; i < MAX_MATERIAL_COLORS; i++) { + material->colors[i] = (Color) { 1, 1, 1, 1 }; + } + for (int i = 0; i < MAX_MATERIAL_TEXTURES; i++) { - if (materialData->textures[i]) { - material->textures[i] = lovrTextureCreate(TEXTURE_2D, &materialData->textures[i], 1, true); - } else { - material->textures[i] = NULL; - } + material->textures[i] = NULL; } return material; @@ -30,11 +29,11 @@ void lovrMaterialDestroy(const Ref* ref) { } Color lovrMaterialGetColor(Material* material, MaterialColor colorType) { - return material->materialData->colors[colorType]; + return material->colors[colorType]; } void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color) { - material->materialData->colors[colorType] = color; + material->colors[colorType] = color; } Texture* lovrMaterialGetTexture(Material* material, MaterialTexture textureType) { diff --git a/src/graphics/material.h b/src/graphics/material.h index 53b80f54..56fd4cfc 100644 --- a/src/graphics/material.h +++ b/src/graphics/material.h @@ -1,18 +1,28 @@ #include "util.h" #include "graphics/texture.h" -#include "data/material.h" #include #pragma once +typedef enum { + COLOR_DIFFUSE, + MAX_MATERIAL_COLORS +} MaterialColor; + +typedef enum { + TEXTURE_DIFFUSE, + TEXTURE_ENVIRONMENT_MAP, + MAX_MATERIAL_TEXTURES +} MaterialTexture; + typedef struct { Ref ref; - MaterialData* materialData; + Color colors[MAX_MATERIAL_COLORS]; Texture* textures[MAX_MATERIAL_TEXTURES]; bool isDefault; } Material; -Material* lovrMaterialCreate(MaterialData* materialData, bool isDefault); +Material* lovrMaterialCreate(bool isDefault); void lovrMaterialDestroy(const Ref* ref); Color lovrMaterialGetColor(Material* material, MaterialColor colorType); void lovrMaterialSetColor(Material* material, MaterialColor colorType, Color color); diff --git a/src/graphics/model.c b/src/graphics/model.c index c2a2395f..14112532 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -33,7 +33,7 @@ static void renderNode(Model* model, int nodeIndex, int instances) { } } - if (!model->material) { + if (!model->material && model->materials) { lovrMeshSetMaterial(model->mesh, model->materials[primitive->material]); } @@ -66,9 +66,30 @@ Model* lovrModelCreate(ModelData* modelData) { lovrMeshSetVertexMap(model->mesh, modelData->indices.data, modelData->indexCount); lovrMeshSetRangeEnabled(model->mesh, true); - model->materials = malloc(modelData->materialCount * sizeof(Material*)); - for (int i = 0; i < modelData->materialCount; i++) { - model->materials[i] = lovrMaterialCreate(modelData->materials[i], false); + if (modelData->textures.length > 0) { + model->textures = malloc(modelData->textures.length * sizeof(Texture*)); + for (int i = 0; i < modelData->textures.length; i++) { + if (modelData->textures.data[i]) { + model->textures[i] = lovrTextureCreate(TEXTURE_2D, (TextureData**) &modelData->textures.data[i], 1, true); + } else { + model->textures[i] = NULL; + } + } + } else { + model->textures = NULL; + } + + if (modelData->materialCount > 0) { + model->materials = malloc(modelData->materialCount * sizeof(Material*)); + for (int i = 0; i < modelData->materialCount; i++) { + ModelMaterial* materialData = &modelData->materials[i]; + Material* material = lovrMaterialCreate(false); + lovrMaterialSetColor(material, COLOR_DIFFUSE, materialData->diffuseColor); + lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, model->textures[materialData->diffuseTexture]); + model->materials[i] = material; + } + } else { + model->materials = NULL; } for (int i = 0; i < MAX_BONES; i++) { @@ -93,6 +114,11 @@ Model* lovrModelCreate(ModelData* modelData) { void lovrModelDestroy(const Ref* ref) { Model* model = containerof(ref, Model); + for (int i = 0; i < model->modelData->textures.length; i++) { + if (model->textures[i]) { + lovrRelease(&model->textures[i]->ref); + } + } for (int i = 0; i < model->modelData->materialCount; i++) { lovrRelease(&model->materials[i]->ref); } @@ -102,6 +128,7 @@ void lovrModelDestroy(const Ref* ref) { if (model->material) { lovrRelease(&model->material->ref); } + free(model->textures); free(model->materials); lovrRelease(&model->modelData->ref); lovrRelease(&model->mesh->ref); diff --git a/src/graphics/model.h b/src/graphics/model.h index add377a0..4bf8289d 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -13,10 +13,11 @@ typedef struct { Ref ref; ModelData* modelData; - Mesh* mesh; + Texture** textures; Material** materials; Material* material; Animator* animator; + Mesh* mesh; float pose[MAX_BONES][16]; float (*nodeTransforms)[16]; float aabb[6]; diff --git a/src/headset/openvr.c b/src/headset/openvr.c index c568aa6b..a4e8a0cd 100644 --- a/src/headset/openvr.c +++ b/src/headset/openvr.c @@ -679,7 +679,7 @@ static ModelData* openvrControllerNewModelData(Controller* controller) { modelData->nodes = malloc(1 * sizeof(ModelNode)); modelData->primitives = malloc(1 * sizeof(ModelPrimitive)); modelData->animations = NULL; - modelData->materials = malloc(1 * sizeof(MaterialData*)); + modelData->materials = malloc(1 * sizeof(ModelMaterial)); // Geometry map_init(&modelData->nodeMap); @@ -700,6 +700,8 @@ static ModelData* openvrControllerNewModelData(Controller* controller) { TextureData* textureData = malloc(sizeof(TextureData)); if (!textureData) return NULL; + vec_push(&modelData->textures, textureData); + int width = vrTexture->unWidth; int height = vrTexture->unHeight; size_t size = width * height * 4; @@ -712,8 +714,8 @@ static ModelData* openvrControllerNewModelData(Controller* controller) { textureData->generateMipmaps = true; vec_init(&textureData->mipmaps); - modelData->materials[0] = lovrMaterialDataCreateEmpty(); - modelData->materials[0]->textures[TEXTURE_DIFFUSE] = textureData; + modelData->materials[0].diffuseColor = (Color) { 1, 1, 1, 1 }; + modelData->materials[0].diffuseTexture = 0; return modelData; }