2 #include <assimp/cimport.h>
3 #include <assimp/postprocess.h>
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);
15 const Asset3D* importAsset(const char* path) {
16 const AiScene* scene = importScene(path);
21 const unsigned int numMeshes = scene->mNumMeshes;
22 const unsigned int numMaterials = scene->mNumMaterials;
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));
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;
35 Mesh mesh = { .numVertices = numVertices,
36 .vertices = malloc(numVertices * sizeof(Vector3D)),
38 .textureCoords = NULL,
40 .faces = malloc(numFaces * sizeof(Face)),
41 .materialIndex = aiMesh->mMaterialIndex };
43 for (unsigned int vertIndex = 0; vertIndex < numVertices; ++vertIndex) {
44 mesh.vertices[vertIndex] = convertAiVector3D(
45 aiMesh->mVertices[vertIndex]);
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]);
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]);
62 for (unsigned int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
63 const AiFace aiFace = aiMesh->mFaces[faceIndex];
64 const unsigned int numIndices = aiFace.mNumIndices;
66 Face face = { .numIndices = numIndices,
67 .indices = malloc(numIndices
68 * sizeof(unsigned int)) };
70 for (unsigned int i = 0; i < numIndices; ++i) {
71 face.indices[i] = aiFace.mIndices[i];
74 mesh.faces[faceIndex] = face;
77 asset->meshes[meshIndex] = mesh;
80 GLuint* textureIds = malloc(numMaterials * sizeof(GLuint));
81 glGenTextures(numMaterials, textureIds);
83 for (unsigned int matIndex = 0; matIndex < numMaterials; ++matIndex) {
84 Material material = { .textureId = textureIds[matIndex] };
86 glBindTexture(GL_TEXTURE_2D, material.textureId);
87 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
89 AiString originalTexturePath;
90 if (aiGetMaterialTexture(scene->mMaterials[matIndex],
91 aiTextureType_DIFFUSE,
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);
101 TgaImage* textureImage = readTga(texturePath);
102 if (textureImage == NULL) {
103 logError("Asset texture file not found: %s", texturePath);
106 glTexImage2D(GL_TEXTURE_2D,
108 textureImage->imageComponents,
109 textureImage->header.imageWidth,
110 textureImage->header.imageHeight,
112 textureImage->imageFormat,
114 textureImage->bytes);
115 free(textureImage->bytes);
120 asset->materials[matIndex] = material;
122 glBindTexture(GL_TEXTURE_2D, 0);
124 aiReleaseImport(scene);
128 static const AiScene* importScene(const char* path) {
129 const AiScene* scene = aiImportFile(path, aiProcess_PreTransformVertices);
131 logError("Failed to import asset from %s", path);
133 else if ((scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) == AI_SCENE_FLAGS_INCOMPLETE) {
134 logError("Incomplete scene imported from %s", path);
135 aiReleaseImport(scene);
141 static Vector3D convertAiVector3D(AiVector3D vect) {
142 return (Vector3D) { .x = vect.x,
148 * The following function will not work properly with texture
149 * file names (excluding directory part) beginning with '.'
151 static const char* replaceFileExtension(const AiString path, const char* ext) {
152 size_t lengthToCopy = path.length;
154 char* lastDotSubstr = strrchr(path.data, '.');
155 if (lastDotSubstr != NULL) {
156 if (strpbrk(lastDotSubstr, "\\/") == NULL) {
157 lengthToCopy = lastDotSubstr - path.data;
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);