]> git.lizzy.rs Git - shadowclad.git/blobdiff - src/engine/asset.c
Add and move version logging, disable import debug
[shadowclad.git] / src / engine / asset.c
index 6be7e2712c284f27158ae3e608a7c4164345f4b7..9261b0236e061f32f8fe2e2e95bcd539fe676c79 100644 (file)
@@ -1,25 +1,99 @@
+#include "asset.h"
+
+#include <math.h>
 #include <stdlib.h>
 #include <assimp/cimport.h>
+//#include <assimp/metadata.h>
 #include <assimp/postprocess.h>
+#include <assimp/scene.h>
 
-#include "asset.h"
-#include "assimp_types.h"
 #include "logger.h"
+#include "string.h"
 #include "tga.h"
 
-static const AiScene* importScene(const char* path);
-static Vector3D convertAiVector3D(AiVector3D vect);
-static const char* replaceFileExtension(const AiString path, const char* ext);
+#define IMPORT_DEBUG_ 0
+
+static const float smoothingThresholdAngle = TAU / 14.0f;
+
+static const struct aiScene* importScene(const char* path);
+static Vector3D triangleNormal(Vector3D v1, Vector3D v2, Vector3D v3);
+static Vector3D convertAiVector3D(struct aiVector3D vect);
+static const char* replaceFileExtension(const struct aiString path, const char* ext);
+
+
+
+#if IMPORT_DEBUG_
+static void printMetadata(const struct aiMetadata* meta) {
+       if (meta) {
+               for (size_t i = 0; i < meta->mNumProperties; ++i) {
+                       String key = stringFromAiString(meta->mKeys[i]);
+                       const struct aiMetadataEntry value = meta->mValues[i];
+                       switch (value.mType) {
+                               case AI_BOOL:
+                                       logDebug("\"%s\": (bool) %d", key.cstr, *((int*) value.mData));
+                                       break;
+                               case AI_INT32:
+                                       logDebug("\"%s\": (int32) %d", key.cstr, *((int32_t*) value.mData));
+                                       break;
+                               case AI_UINT64:
+                                       logDebug("\"%s\": (uint64) %llu", key.cstr, *((uint64_t*) value.mData));
+                                       break;
+                               case AI_FLOAT:
+                                       logDebug("\"%s\": (float) %f", key.cstr, *((float*) value.mData));
+                                       break;
+                               case AI_DOUBLE:
+                                       logDebug("\"%s\": (double) %f", key.cstr, *((double*) value.mData));
+                                       break;
+                               case AI_AISTRING: {
+                                       String str = stringFromAiString(*((struct aiString*) value.mData));
+                                       logDebug("\"%s\": (string) %s", key.cstr, str.cstr);
+                                       dropString(str);
+                                       break; }
+                               case AI_AIVECTOR3D: {
+                                       struct aiVector3D vec = *((struct aiVector3D*) value.mData);
+                                       logDebug("\"%s\": (vector3d) { %f, %f, %f }", key.cstr, vec.x, vec.y, vec.z);
+                                       break; }
+                               case AI_META_MAX:
+                               default:
+                                       logDebug("\"%s\": (unrecognized type)", key.cstr);
+                                       break;
+                       }
+                       dropString(key);
+               }
+       }
+}
+
+void printAiNodeMetadata(const struct aiNode* node) {
+       if (!node) {
+               return;
+       }
 
+       String name = stringFromAiString(node->mName);
+       logDebug("Metadata from node \"%s\": %p", name.cstr, node->mMetaData);
+       printMetadata(node->mMetaData);
 
+       for (size_t i = 0; i < node->mNumChildren; ++i) {
+               printAiNodeMetadata(node->mChildren[i]);
+       }
+
+       dropString(name);
+}
+#endif // IMPORT_DEBUG_
 
 const Solid* importSolid(const char* path) {
-       const AiScene* scene = importScene(path);
+       const struct aiScene* scene = importScene(path);
        if (scene == NULL) {
                logError("Failed to import solid from %s", path);
                return NULL;
        }
        
+#if IMPORT_DEBUG_
+       const struct aiMetadata* meta = scene->mMetaData;
+       logDebug("Metadata from %s: %p", path, meta);
+       printMetadata(meta);
+       printAiNodeMetadata(scene->mRootNode);
+#endif // IMPORT_DEBUG_
+       
        const unsigned int numMeshes = scene->mNumMeshes;
        const unsigned int numMaterials = scene->mNumMaterials;
 
@@ -32,7 +106,7 @@ const Solid* importSolid(const char* path) {
        solid->materials = malloc(numMaterials * sizeof(Material));
        
        for (unsigned int meshIndex = 0; meshIndex < numMeshes; ++meshIndex) {
-               const AiMesh* aiMesh = scene->mMeshes[meshIndex];
+               const struct aiMesh* aiMesh = scene->mMeshes[meshIndex];
                const unsigned int numVertices = aiMesh->mNumVertices;
                const unsigned int numFaces = aiMesh->mNumFaces;
                
@@ -64,18 +138,75 @@ const Solid* importSolid(const char* path) {
                }
                
                for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
-                       const AiFace aiFace = aiMesh->mFaces[faceIndex];
+                       const struct aiFace aiFace = aiMesh->mFaces[faceIndex];
                        const unsigned int numIndices = aiFace.mNumIndices;
                        
                        Face face = { .numIndices = numIndices,
-                                     .indices = malloc(numIndices * sizeof(size_t)) };
+                                     .indices = malloc(numIndices * sizeof(size_t)),
+                                     .normals = malloc(numIndices * sizeof(Vector3D)) };
                        
                        for (unsigned int i = 0; i < numIndices; ++i) {
                                face.indices[i] = aiFace.mIndices[i];
                        }
                        
+                       if (numIndices == 3) {
+                               Vector3D normal = triangleNormal(mesh.vertices[face.indices[0]],
+                                                                mesh.vertices[face.indices[1]],
+                                                                mesh.vertices[face.indices[2]]);
+                               for (size_t i = 0; i < numIndices; ++i) {
+                                       face.normals[i] = normal;
+                               }
+                       }
+                       else {
+                               if (mesh.normals) {
+                                       for (size_t i = 0; i < numIndices; ++i) {
+                                               face.normals[i] = mesh.normals[face.indices[i]];
+                                       }
+                               }
+                               else {
+                                       free(face.normals);
+                                       face.normals = NULL;
+                               }
+                       }
+                       
                        mesh.faces[faceIndex] = face;
                }
+
+               float smoothingThreshold = cosf(smoothingThresholdAngle);
+               Face* smoothedFaces = malloc(mesh.numFaces * sizeof(Face));
+               for (size_t faceIndex = 0; faceIndex < mesh.numFaces; ++faceIndex) {
+                       Face face = mesh.faces[faceIndex];
+
+                       if (face.normals) {
+                               face.normals = memcpy(malloc(face.numIndices * sizeof(Vector3D)),
+                                                     face.normals,
+                                                     face.numIndices * sizeof(Vector3D));
+
+                               for (size_t indexIndex = 0; indexIndex < face.numIndices; ++indexIndex) {
+                                       Vector3D smoothedNormal = face.normals[indexIndex];
+
+                                       for (size_t i = 0; i < mesh.numFaces; ++i) {
+                                               if (i == faceIndex || !mesh.faces[i].normals) {
+                                                       continue;
+                                               }
+
+                                               for (size_t k = 0; k < mesh.faces[i].numIndices; ++k) {
+                                                       if (mesh.faces[i].indices[k] == face.indices[indexIndex]
+                                                           && dotProduct(face.normals[indexIndex],
+                                                                         mesh.faces[i].normals[k]) >= smoothingThreshold) {
+                                                               smoothedNormal = addVectors(smoothedNormal, mesh.faces[i].normals[k]);
+                                                       }
+                                               }
+                                       }
+
+                                       face.normals[indexIndex] = normalized(smoothedNormal);
+                               }
+                       }
+                       smoothedFaces[faceIndex] = face;
+               }
+               // TODO Actually clean up the stuff inside
+               free(mesh.faces);
+               mesh.faces = smoothedFaces;
                
                solid->meshes[meshIndex] = mesh;
        }
@@ -85,11 +216,27 @@ const Solid* importSolid(const char* path) {
        
        for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) {
                Material material = { .textureId = textureIds[matIndex] };
+
+#if IMPORT_DEBUG_
+               const struct aiMaterialProperty* prop;
+               aiGetMaterialProperty(scene->mMaterials[matIndex],
+                                     AI_MATKEY_SHADING_MODEL,
+                                     &prop);
+
+               String key = stringFromAiString(prop->mKey);
+
+               logDebug("Material property \"%s\": Shading model: (length %u) %d",
+                        key.cstr,
+                        prop->mDataLength,
+                        *((int32_t*) prop->mData));
+
+               dropString(key);
+#endif // IMPORT_DEBUG_
                
                glBindTexture(GL_TEXTURE_2D, material.textureId);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                
-               AiString originalTexturePath;
+               struct aiString originalTexturePath;
                if (aiGetMaterialTexture(scene->mMaterials[matIndex],
                                         aiTextureType_DIFFUSE,
                                         0,
@@ -128,8 +275,10 @@ const Solid* importSolid(const char* path) {
        return solid;
 }
 
-static const AiScene* importScene(const char* path) {
-       const AiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices);
+static const struct aiScene* importScene(const char* path) {
+       const struct aiScene* scene = aiImportFile(path, aiProcess_JoinIdenticalVertices
+                                                        | aiProcess_PreTransformVertices
+                                                        | aiProcess_ValidateDataStructure);
        if (scene != NULL && scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
                logError("Incomplete scene imported from %s", path);
                aiReleaseImport(scene);
@@ -138,7 +287,11 @@ static const AiScene* importScene(const char* path) {
        return scene;
 }
 
-static Vector3D convertAiVector3D(AiVector3D vect) {
+static Vector3D triangleNormal(Vector3D v1, Vector3D v2, Vector3D v3) {
+       return normalized(crossProduct(subtractVectors(v2, v1), subtractVectors(v3, v1)));
+}
+
+static Vector3D convertAiVector3D(struct aiVector3D vect) {
        return (Vector3D) { .x = vect.x,
                            .y = vect.y,
                            .z = vect.z };
@@ -149,7 +302,7 @@ static Vector3D convertAiVector3D(AiVector3D vect) {
  * The following function will not work properly with texture
  * file names (excluding directory part) beginning with '.'
  */
-static const char* replaceFileExtension(const AiString path, const char* ext) {
+static const char* replaceFileExtension(const struct aiString path, const char* ext) {
                size_t lengthToCopy = path.length;
                
                char* lastDotSubstr = strrchr(path.data, '.');