e53e5a3204ca8065e78db702411f0d6d51fa14b8
[demo] / src / scene.cc
1 #include <assert.h>
2
3 #include <assimp/cimport.h>
4 #include <assimp/material.h>
5 #include <assimp/mesh.h>
6 #include <assimp/postprocess.h>
7 #include <assimp/scene.h>
8
9 #include <string>
10
11 #include <gmath/gmath.h>
12
13 #include "mesh.h"
14 #include "object.h"
15 #include "scene.h"
16 #include "texture.h"
17
18 #include "opengl/mesh-gl.h"
19 #include "vulkan/mesh-vk.h"
20
21 #include "opengl/texture-gl.h"
22 #include "vulkan/texture-vk.h"
23
24 extern bool use_vulkan;
25 static Mesh *load_mesh(const aiScene *scene, unsigned int index);
26 static Material *load_material(const aiScene *ascene, Scene *scene, unsigned int index);
27
28 Scene::Scene() {}
29
30 Scene::~Scene()
31 {
32         /* clear meshes */
33         for(size_t i=0; i<meshes.size(); ++i)
34                 delete meshes[i];
35         meshes.clear();
36
37         /* clear materials */
38         for(size_t i=0; i<materials.size(); ++i)
39                 delete materials[i];
40         materials.clear();
41
42         /* clear textures */
43         for(size_t i= 0; i<textures.size(); ++i)
44                 delete textures[i];
45         textures.clear();
46 }
47
48 bool Scene::load(const char *fname)
49 {
50         /* loading scene */
51         unsigned int ai_flags = aiProcessPreset_TargetRealtime_Quality;
52         const aiScene *scene = aiImportFile(fname, ai_flags);
53         if(!scene) {
54                 fprintf(stderr, "Failed to import scene: %s\n", fname);
55                 return false;
56         }
57
58         /* loading scene meshes */
59         for(unsigned int i=0; i<scene->mNumMeshes; ++i) {
60                 Mesh *mesh = load_mesh(scene, i);
61                 if(!mesh) {
62                         fprintf(stderr, "Failed to load mesh no: %d.\n", i);
63                         return false;
64                 }
65                 meshes.push_back(mesh);
66         }
67
68         /* loading materials */
69         for(unsigned int i=0; i<scene->mNumMaterials; ++i) {
70                 Material *material = load_material(scene, this, i);
71                 if(!material) {
72                         fprintf(stderr, "Failed to load material no: %d", i);
73                         return false;
74                 }
75                 materials.push_back(material);
76         }
77
78         /* create objects */
79
80
81         aiReleaseImport(scene);
82         return true;
83 }
84
85 static Mesh *load_mesh(const aiScene *scene, unsigned int index)
86 {
87         /* load mesh with index from scene using assimp */
88         aiMesh *amesh = scene->mMeshes[index];
89         if(!amesh) {
90                 fprintf(stderr, "Failed to load assimp mesh no: %d.\n", index);
91                 return 0;
92         }
93
94         Mesh *mesh;
95         if(use_vulkan) {
96                 mesh = new MeshVK;
97         }
98         else {
99                 mesh = new MeshGL;
100         }
101
102         mesh->name = std::string(amesh->mName.data);
103         mesh->which_mask = 0;
104
105         for(unsigned int i=0; i<amesh->mNumVertices; ++i) {
106                 /* vertices */
107                 if(amesh->HasPositions()) {
108                         mesh->which_mask |= MESH_VERTEX;
109                         Vec3 vertex = Vec3(amesh->mVertices[i].x, amesh->mVertices[i].y,
110                                            amesh->mVertices[i].z);
111
112                         mesh->vertices.push_back(vertex);
113                 }
114                 else {
115                         fprintf(stderr, "Mesh has no geometry!\n");
116                         delete mesh;
117                         return 0;
118                 }
119
120                 /* normals */
121                 if(amesh->HasNormals()) {
122                         mesh->which_mask |= MESH_NORMAL;
123                         Vec3 normal = Vec3(amesh->mNormals[i].x, amesh->mNormals[i].y,
124                                            amesh->mNormals[i].z);
125                         mesh->normals.push_back(normal);
126                 }
127                 else {
128                         fprintf(stderr, "Mesh has no normals!\n");
129                         delete mesh;
130                         return 0;
131                 }
132
133                 /* texture coordinates */
134                 if(amesh->mTextureCoords[0]) {
135                         mesh->which_mask |= MESH_TEXTURE;
136                         Vec2 tex_coord =
137                             Vec2(amesh->mTextureCoords[0][i].x, amesh->mTextureCoords[0][i].y);
138                         mesh->tex_coords.push_back(tex_coord);
139                 }
140                 else {
141                         mesh->tex_coords.push_back(Vec2(0, 0));
142                 }
143
144                 /* tangents */
145                 if(amesh->mTangents) {
146                         mesh->which_mask |= MESH_TANGENT;
147                         Vec3 tangent = Vec3(amesh->mTangents[i].x, amesh->mTangents[i].y,
148                                             amesh->mTangents[i].z);
149                         mesh->tangents.push_back(tangent);
150                 }
151                 else {
152                         mesh->tangents.push_back(Vec3(1, 0, 0));
153                 }
154         }
155         /* indices (called faces in assimp) */
156         if(amesh->HasFaces()) {
157                 mesh->which_mask |= MESH_INDEX;
158                 for(unsigned int i=0; i<amesh->mNumFaces; ++i) {
159                         mesh->indices.push_back(amesh->mFaces[i].mIndices[0]);
160                         mesh->indices.push_back(amesh->mFaces[i].mIndices[1]);
161                         mesh->indices.push_back(amesh->mFaces[i].mIndices[2]);
162                 }
163         }
164         else
165                 fprintf(stderr, "No faces found.\n");
166
167         return mesh;
168 }
169
170 static Material *load_material(const aiScene *ascene, Scene *scene, unsigned int index)
171 {
172         aiMaterial *amat = ascene->mMaterials[index];
173         if(!amat) {
174                 fprintf(stderr, "Failed to load material no: %d.\n", index);
175                 return 0;
176         }
177
178         Material *mat = new Material;
179         mat->dtex = 0;
180         mat->shininess = 40;
181
182         // mat->name = std::string(amat->name.data);
183
184         aiColor4D color;
185         aiGetMaterialColor(amat, AI_MATKEY_COLOR_DIFFUSE, &color);
186         mat->diffuse = Vec3(color.r, color.g, color.b);
187
188         aiGetMaterialColor(amat, AI_MATKEY_COLOR_SPECULAR, &color);
189         float spstr;
190         aiGetMaterialFloat(amat, AI_MATKEY_SHININESS_STRENGTH, &spstr);
191         mat->specular = spstr * Vec3(color.r, color.g, color.b);
192
193         aiGetMaterialFloat(amat, AI_MATKEY_SHININESS, &mat->shininess);
194
195         aiString tex_name;
196         if(aiGetMaterialString(amat, AI_MATKEY_TEXTURE_DIFFUSE(0), &tex_name) == aiReturn_SUCCESS) {
197                 /* different scene objects might use the same texture, we shouldn't store it twice*/
198                 //mat->dtex = scene->find_texture(tex_name.data);
199                 if(!mat->dtex) {
200                         if(use_vulkan) {
201                                 mat->dtex = new TextureVK;
202                         }
203                         else {
204                                 mat->dtex = new TextureGL;
205                         }
206                         if(!mat->dtex->load(tex_name.data)) {
207                                 fprintf(stderr, "Failed to load texture data: %s.\n", tex_name.data);
208                                 delete mat->dtex;
209                                 mat->dtex = 0;
210                         }
211                         scene->textures.push_back(mat->dtex);
212                 }
213         }
214
215         return mat;
216 }