]> git.lizzy.rs Git - shadowclad.git/blob - src/asset.c
Remove nonsense pointer comparison
[shadowclad.git] / src / asset.c
1 #include <stdlib.h>
2 #include <assimp/cimport.h>
3 #include <assimp/postprocess.h>
4
5 #include "asset.h"
6 #include "logger.h"
7 #include "tga.h"
8
9 static const AiScene* importScene(const char* path);
10 static Vector3D convertAiVector3D(AiVector3D vect);
11 static const char* replaceFileExtension(const AiString path, const char* ext);
12
13
14
15 const Asset3D* importAsset(const char* path) {
16         const AiScene* scene = importScene(path);
17         if (scene == NULL) {
18                 return NULL;
19         }
20         
21         const unsigned int numMeshes = scene->mNumMeshes;
22         const unsigned int numMaterials = scene->mNumMaterials;
23         
24         Asset3D* asset = malloc(sizeof(Asset3D));
25         asset->numMeshes = numMeshes;
26         asset->meshes = malloc(numMeshes * sizeof(Mesh));
27         asset->numMaterials = numMaterials;
28         asset->materials = malloc(numMaterials * sizeof(Material));
29         
30         for (unsigned int meshIndex = 0; meshIndex < numMeshes; ++meshIndex) {
31                 const AiMesh* aiMesh = scene->mMeshes[meshIndex];
32                 const unsigned int numVertices = aiMesh->mNumVertices;
33                 const unsigned int numFaces = aiMesh->mNumFaces;
34                 
35                 Mesh mesh = { .numVertices = numVertices,
36                               .vertices = malloc(numVertices * sizeof(Vector3D)),
37                               .normals = NULL,
38                               .textureCoords = NULL,
39                               .numFaces = numFaces,
40                               .faces = malloc(numFaces * sizeof(Face)),
41                               .materialIndex = aiMesh->mMaterialIndex };
42                 
43                 for (unsigned int vertIndex = 0; vertIndex < numVertices; ++vertIndex) {
44                         mesh.vertices[vertIndex] = convertAiVector3D(
45                                         aiMesh->mVertices[vertIndex]);
46                 }
47                 
48                 if (aiMesh->mNormals != NULL) {
49                         mesh.normals = malloc(numVertices * sizeof(Vector3D));
50                         for (unsigned int normIndex = 0; normIndex < numVertices; ++normIndex) {
51                                 mesh.normals[normIndex] = convertAiVector3D(
52                                                 aiMesh->mNormals[normIndex]);
53                         }
54                 }
55                 
56                 mesh.textureCoords = malloc(numVertices * sizeof(Vector3D));
57                 for (unsigned int texcIndex = 0; texcIndex < numVertices; ++texcIndex) {
58                         mesh.textureCoords[texcIndex] = convertAiVector3D(
59                                         aiMesh->mTextureCoords[0][texcIndex]);
60                 }
61                 
62                 for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
63                         const AiFace aiFace = aiMesh->mFaces[faceIndex];
64                         const unsigned int numIndices = aiFace.mNumIndices;
65                         
66                         Face face = { .numIndices = numIndices,
67                                       .indices = malloc(numIndices
68                                                         * sizeof(unsigned int)) };
69                         
70                         for (unsigned int i = 0; i < numIndices; ++i) {
71                                 face.indices[i] = aiFace.mIndices[i];
72                         }
73                         
74                         mesh.faces[faceIndex] = face;
75                 }
76                 
77                 asset->meshes[meshIndex] = mesh;
78         }
79         
80         GLuint* textureIds = malloc(numMaterials * sizeof(GLuint));
81         glGenTextures(numMaterials, textureIds);
82         
83         for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) {
84                 Material material = { .textureId = textureIds[matIndex] };
85                 
86                 glBindTexture(GL_TEXTURE_2D, material.textureId);
87                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
88                 
89                 AiString originalTexturePath;
90                 if (aiGetMaterialTexture(scene->mMaterials[matIndex],
91                                          aiTextureType_DIFFUSE,
92                                          0,
93                                          &originalTexturePath,
94                                          NULL, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
95                         const char* textureFile = replaceFileExtension(originalTexturePath, ".tga");
96                         const size_t textureFileLength = strlen(textureFile);
97                         char* texturePath = malloc(strlen("assets/") + textureFileLength + 1);
98                         strcpy(texturePath, "assets/");
99                         strncat(texturePath, textureFile, textureFileLength);
100                         
101                         TgaImage* textureImage = readTga(texturePath);
102                         if (textureImage == NULL) {
103                                 logError("Asset texture file not found: %s", texturePath);
104                         }
105                         else {
106                                 glTexImage2D(GL_TEXTURE_2D,
107                                              0,
108                                              textureImage->imageComponents,
109                                              textureImage->header.imageWidth,
110                                              textureImage->header.imageHeight,
111                                              0,
112                                              textureImage->imageFormat,
113                                              GL_UNSIGNED_BYTE,
114                                              textureImage->bytes);
115                                 free(textureImage->bytes);
116                                 free(textureImage);
117                         }
118                 }
119                 
120                 asset->materials[matIndex] = material;
121         }
122         glBindTexture(GL_TEXTURE_2D, 0);
123         
124         aiReleaseImport(scene);
125         return asset;
126 }
127
128 static const AiScene* importScene(const char* path) {
129         const AiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices);
130         if (scene == NULL) {
131                 logError("Failed to import asset from %s", path);
132         }
133         else if ((scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) == AI_SCENE_FLAGS_INCOMPLETE) {
134                 logError("Incomplete scene imported from %s", path);
135                 aiReleaseImport(scene);
136                 scene = NULL;
137         }
138         return scene;
139 }
140
141 static Vector3D convertAiVector3D(AiVector3D vect) {
142         return (Vector3D) { .x = vect.x,
143                             .y = vect.y,
144                             .z = vect.z };
145 }
146
147 /** BUGS
148  * The following function will not work properly with texture
149  * file names (excluding directory part) beginning with '.'
150  */
151 static const char* replaceFileExtension(const AiString path, const char* ext) {
152                 size_t lengthToCopy = path.length;
153                 
154                 char* lastDotSubstr = strrchr(path.data, '.');
155                 if (lastDotSubstr != NULL) {
156                         if (strpbrk(lastDotSubstr, "\\/") == NULL) {
157                                 lengthToCopy = lastDotSubstr - path.data;
158                         }
159                 }
160                 
161                 size_t extLength = strlen(ext) + 1;
162                 char* newPath = malloc(lengthToCopy + extLength);
163                 strncpy(newPath, path.data, lengthToCopy);
164                 strncpy(newPath + lengthToCopy, ext, extLength);
165                 
166                 return newPath;
167 }