2 #include <assimp/cimport.h>
3 #include <assimp/postprocess.h>
4 #include <assimp/scene.h>
10 static const struct aiScene* importScene(const char* path);
11 static Vector3D convertAiVector3D(struct aiVector3D vect);
12 static const char* replaceFileExtension(const struct aiString path, const char* ext);
16 const Solid* importSolid(const char* path) {
17 const struct aiScene* scene = importScene(path);
19 logError("Failed to import solid from %s", path);
23 const unsigned int numMeshes = scene->mNumMeshes;
24 const unsigned int numMaterials = scene->mNumMaterials;
26 // TODO Consider assets with some arrays empty, and prevent zero mallocs
28 Solid* solid = malloc(sizeof(Solid));
29 solid->numMeshes = numMeshes;
30 solid->meshes = malloc(numMeshes * sizeof(Mesh));
31 solid->numMaterials = numMaterials;
32 solid->materials = malloc(numMaterials * sizeof(Material));
34 for (unsigned int meshIndex = 0; meshIndex < numMeshes; ++meshIndex) {
35 const struct aiMesh* aiMesh = scene->mMeshes[meshIndex];
36 const unsigned int numVertices = aiMesh->mNumVertices;
37 const unsigned int numFaces = aiMesh->mNumFaces;
39 Mesh mesh = { .numVertices = numVertices,
40 .vertices = malloc(numVertices * sizeof(Vector3D)),
42 .textureCoords = NULL,
44 .faces = malloc(numFaces * sizeof(Face)),
45 .materialIndex = aiMesh->mMaterialIndex };
47 for (unsigned int vertIndex = 0; vertIndex < numVertices; ++vertIndex) {
48 mesh.vertices[vertIndex] = convertAiVector3D(
49 aiMesh->mVertices[vertIndex]);
52 if (aiMesh->mNormals != NULL) {
53 mesh.normals = malloc(numVertices * sizeof(Vector3D));
54 for (unsigned int normIndex = 0; normIndex < numVertices; ++normIndex) {
55 mesh.normals[normIndex] = convertAiVector3D(
56 aiMesh->mNormals[normIndex]);
60 mesh.textureCoords = malloc(numVertices * sizeof(Vector3D));
61 for (unsigned int texcIndex = 0; texcIndex < numVertices; ++texcIndex) {
62 mesh.textureCoords[texcIndex] = convertAiVector3D(
63 aiMesh->mTextureCoords[0][texcIndex]);
66 for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
67 const struct aiFace aiFace = aiMesh->mFaces[faceIndex];
68 const unsigned int numIndices = aiFace.mNumIndices;
70 Face face = { .numIndices = numIndices,
71 .indices = malloc(numIndices * sizeof(size_t)) };
73 for (unsigned int i = 0; i < numIndices; ++i) {
74 face.indices[i] = aiFace.mIndices[i];
77 mesh.faces[faceIndex] = face;
80 solid->meshes[meshIndex] = mesh;
83 GLuint* textureIds = malloc(numMaterials * sizeof(GLuint));
84 glGenTextures(numMaterials, textureIds);
86 for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) {
87 Material material = { .textureId = textureIds[matIndex] };
89 glBindTexture(GL_TEXTURE_2D, material.textureId);
90 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
92 struct aiString originalTexturePath;
93 if (aiGetMaterialTexture(scene->mMaterials[matIndex],
94 aiTextureType_DIFFUSE,
97 NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
98 const char* textureFilename = replaceFileExtension(originalTexturePath, ".tga");
99 const size_t textureFilenameLength = strlen(textureFilename);
100 char* texturePath = malloc(strlen("assets/") + textureFilenameLength + 1);
101 strcpy(texturePath, "assets/");
102 strncat(texturePath, textureFilename, textureFilenameLength);
104 TgaImage* textureImage = readTga(texturePath);
105 if (textureImage == NULL) {
106 logError("Importing solid from %s: Cannot read texture file %s", path, texturePath);
109 glTexImage2D(GL_TEXTURE_2D,
111 textureImage->imageComponents,
112 textureImage->header.imageWidth,
113 textureImage->header.imageHeight,
115 textureImage->imageFormat,
117 textureImage->bytes);
118 free(textureImage->bytes);
123 solid->materials[matIndex] = material;
125 glBindTexture(GL_TEXTURE_2D, 0);
127 aiReleaseImport(scene);
131 static const struct aiScene* importScene(const char* path) {
132 const struct aiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices);
133 if (scene != NULL && scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
134 logError("Incomplete scene imported from %s", path);
135 aiReleaseImport(scene);
141 static Vector3D convertAiVector3D(struct aiVector3D vect) {
142 return (Vector3D) { .x = vect.x,
149 * The following function will not work properly with texture
150 * file names (excluding directory part) beginning with '.'
152 static const char* replaceFileExtension(const struct aiString path, const char* ext) {
153 size_t lengthToCopy = path.length;
155 char* lastDotSubstr = strrchr(path.data, '.');
156 if (lastDotSubstr != NULL) {
157 if (strpbrk(lastDotSubstr, "\\/") == NULL) {
158 lengthToCopy = lastDotSubstr - path.data;
162 size_t extLength = strlen(ext) + 1;
163 char* newPath = malloc(lengthToCopy + extLength);
164 strncpy(newPath, path.data, lengthToCopy);
165 strncpy(newPath + lengthToCopy, ext, extLength);