4 #include <assimp/cimport.h>
5 //#include <assimp/metadata.h>
6 #include <assimp/postprocess.h>
7 #include <assimp/scene.h>
12 #define IMPORT_DEBUG_ 1
14 static const struct aiScene* importScene(const char* path);
15 static Vector3D convertAiVector3D(struct aiVector3D vect);
16 static const char* replaceFileExtension(const struct aiString path, const char* ext);
21 static void printMetadata(const struct aiMetadata* meta) {
23 for (size_t i = 0; i < meta->mNumProperties; ++i) {
24 char* key = memcpy(malloc((meta->mKeys[i].length + 1) * sizeof(char)),
26 meta->mKeys[i].length * sizeof(char));
27 key[meta->mKeys[i].length] = '\0';
28 const struct aiMetadataEntry value = meta->mValues[i];
29 switch (value.mType) {
31 logDebug("\"%s\": (bool) %d", key, *((int*) value.mData));
34 logDebug("\"%s\": (int32) %d", key, *((int32_t*) value.mData));
37 logDebug("\"%s\": (uint64) %llu", key, *((uint64_t*) value.mData));
40 logDebug("\"%s\": (float) %f", key, *((float*) value.mData));
43 logDebug("\"%s\": (double) %f", key, *((double*) value.mData));
46 struct aiString aistr = *((struct aiString*) value.mData);
47 char* str = memcpy(malloc((aistr.length + 1) * sizeof(char)),
49 aistr.length * sizeof(char));
50 str[aistr.length] = '\0';
51 logDebug("\"%s\": (string) %s", key, str);
55 struct aiVector3D vec = *((struct aiVector3D*) value.mData);
56 logDebug("\"%s\": (vector3d) { %f, %f, %f }", key, vec.x, vec.y, vec.z);
60 logDebug("\"%s\": (unrecognized type)", key);
68 void printAiNodeMetadata(const struct aiNode* node) {
73 struct aiString aistr = node->mName;
74 char* name = memcpy(malloc((aistr.length + 1) * sizeof(char)),
76 aistr.length * sizeof(char));
77 name[aistr.length] = '\0';
78 logDebug("Metadata from node \"%s\": %p", name, node->mMetaData);
79 printMetadata(node->mMetaData);
81 for (size_t i = 0; i < node->mNumChildren; ++i) {
82 printAiNodeMetadata(node->mChildren[i]);
85 #endif // IMPORT_DEBUG_
87 const Solid* importSolid(const char* path) {
88 const struct aiScene* scene = importScene(path);
90 logError("Failed to import solid from %s", path);
95 const struct aiMetadata* meta = scene->mMetaData;
96 logDebug("Metadata from %s: %p", path, meta);
98 printAiNodeMetadata(scene->mRootNode);
99 #endif // IMPORT_DEBUG_
101 const unsigned int numMeshes = scene->mNumMeshes;
102 const unsigned int numMaterials = scene->mNumMaterials;
104 // TODO Consider assets with some arrays empty, and prevent zero mallocs
106 Solid* solid = malloc(sizeof(Solid));
107 solid->numMeshes = numMeshes;
108 solid->meshes = malloc(numMeshes * sizeof(Mesh));
109 solid->numMaterials = numMaterials;
110 solid->materials = malloc(numMaterials * sizeof(Material));
112 for (unsigned int meshIndex = 0; meshIndex < numMeshes; ++meshIndex) {
113 const struct aiMesh* aiMesh = scene->mMeshes[meshIndex];
114 const unsigned int numVertices = aiMesh->mNumVertices;
115 const unsigned int numFaces = aiMesh->mNumFaces;
117 Mesh mesh = { .numVertices = numVertices,
118 .vertices = malloc(numVertices * sizeof(Vector3D)),
120 .textureCoords = NULL,
121 .numFaces = numFaces,
122 .faces = malloc(numFaces * sizeof(Face)),
123 .materialIndex = aiMesh->mMaterialIndex };
125 for (unsigned int vertIndex = 0; vertIndex < numVertices; ++vertIndex) {
126 mesh.vertices[vertIndex] = convertAiVector3D(
127 aiMesh->mVertices[vertIndex]);
130 if (aiMesh->mNormals != NULL) {
131 mesh.normals = malloc(numVertices * sizeof(Vector3D));
132 for (unsigned int normIndex = 0; normIndex < numVertices; ++normIndex) {
133 mesh.normals[normIndex] = convertAiVector3D(
134 aiMesh->mNormals[normIndex]);
138 mesh.textureCoords = malloc(numVertices * sizeof(Vector3D));
139 for (unsigned int texcIndex = 0; texcIndex < numVertices; ++texcIndex) {
140 mesh.textureCoords[texcIndex] = convertAiVector3D(
141 aiMesh->mTextureCoords[0][texcIndex]);
144 for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
145 const struct aiFace aiFace = aiMesh->mFaces[faceIndex];
146 const unsigned int numIndices = aiFace.mNumIndices;
148 Face face = { .numIndices = numIndices,
149 .indices = malloc(numIndices * sizeof(size_t)) };
151 for (unsigned int i = 0; i < numIndices; ++i) {
152 face.indices[i] = aiFace.mIndices[i];
155 mesh.faces[faceIndex] = face;
158 solid->meshes[meshIndex] = mesh;
161 GLuint* textureIds = malloc(numMaterials * sizeof(GLuint));
162 glGenTextures(numMaterials, textureIds);
164 for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) {
165 Material material = { .textureId = textureIds[matIndex] };
168 const struct aiMaterialProperty* prop;
169 aiGetMaterialProperty(scene->mMaterials[matIndex],
170 AI_MATKEY_SHADING_MODEL,
173 struct aiString aistr = prop->mKey;
174 char* key = memcpy(malloc((aistr.length + 1) * sizeof(char)),
176 aistr.length * sizeof(char));
177 key[aistr.length] = '\0';
179 logDebug("Material property \"%s\": Shading model: (length %u) %d",
182 *((int32_t*) prop->mData));
183 #endif // IMPORT_DEBUG_
185 glBindTexture(GL_TEXTURE_2D, material.textureId);
186 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188 struct aiString originalTexturePath;
189 if (aiGetMaterialTexture(scene->mMaterials[matIndex],
190 aiTextureType_DIFFUSE,
192 &originalTexturePath,
193 NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
194 const char* textureFilename = replaceFileExtension(originalTexturePath, ".tga");
195 const size_t textureFilenameLength = strlen(textureFilename);
196 char* texturePath = malloc(strlen("assets/") + textureFilenameLength + 1);
197 strcpy(texturePath, "assets/");
198 strncat(texturePath, textureFilename, textureFilenameLength);
200 TgaImage* textureImage = readTga(texturePath);
201 if (textureImage == NULL) {
202 logError("Importing solid from %s: Cannot read texture file %s", path, texturePath);
205 glTexImage2D(GL_TEXTURE_2D,
207 textureImage->imageComponents,
208 textureImage->header.imageWidth,
209 textureImage->header.imageHeight,
211 textureImage->imageFormat,
213 textureImage->bytes);
214 free(textureImage->bytes);
219 solid->materials[matIndex] = material;
221 glBindTexture(GL_TEXTURE_2D, 0);
223 aiReleaseImport(scene);
227 static const struct aiScene* importScene(const char* path) {
228 const struct aiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices);
229 if (scene != NULL && scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
230 logError("Incomplete scene imported from %s", path);
231 aiReleaseImport(scene);
237 static Vector3D convertAiVector3D(struct aiVector3D vect) {
238 return (Vector3D) { .x = vect.x,
245 * The following function will not work properly with texture
246 * file names (excluding directory part) beginning with '.'
248 static const char* replaceFileExtension(const struct aiString path, const char* ext) {
249 size_t lengthToCopy = path.length;
251 char* lastDotSubstr = strrchr(path.data, '.');
252 if (lastDotSubstr != NULL) {
253 if (strpbrk(lastDotSubstr, "\\/") == NULL) {
254 lengthToCopy = lastDotSubstr - path.data;
258 size_t extLength = strlen(ext) + 1;
259 char* newPath = malloc(lengthToCopy + extLength);
260 strncpy(newPath, path.data, lengthToCopy);
261 strncpy(newPath + lengthToCopy, ext, extLength);