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