quick backup of the renderer - things missing
[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 static Mat4 aiMatrix2Mat(aiMatrix4x4 t);
29 static void create_object(aiNode *node, Mat4 transform, Scene *scene, const aiScene *ascene);
30
31 Scene::Scene() {}
32
33 Scene::~Scene()
34 {
35         for(size_t i=0; i<meshes.size(); ++i)
36                 delete meshes[i];
37         meshes.clear();
38
39         for(size_t i=0; i<materials.size(); ++i)
40                 delete materials[i];
41         materials.clear();
42
43         for(size_t i=0; i<textures.size(); ++i)
44                 delete textures[i];
45         textures.clear();
46
47         for(size_t i=0; i<objects.size(); ++i)
48                 delete objects[i];
49         objects.clear();
50 }
51
52 bool Scene::load(const char *fname)
53 {
54         /* loading scene */
55         unsigned int ai_flags = aiProcessPreset_TargetRealtime_Quality;
56         const aiScene *scene = aiImportFile(fname, ai_flags);
57         if(!scene) {
58                 fprintf(stderr, "Failed to import scene: %s\n", fname);
59                 return false;
60         }
61
62         /* load meshes */
63         for(unsigned int i=0; i<scene->mNumMeshes; ++i) {
64                 Mesh *mesh = load_mesh(scene, i);
65                 if(!mesh) {
66                         fprintf(stderr, "Failed to load mesh no: %d.\n", i);
67                         return false;
68                 }
69                 meshes.push_back(mesh);
70         }
71
72         /* load materials */
73         for(unsigned int i=0; i<scene->mNumMaterials; ++i) {
74                 Material *material = load_material(scene, this, i);
75                 if(!material) {
76                         fprintf(stderr, "Failed to load material no: %d", i);
77                         return false;
78                 }
79                 materials.push_back(material);
80         }
81
82         /* create objects */
83         aiNode *node = scene->mRootNode;
84         Mat4 transform = Mat4::identity;
85         create_object(node, transform, this, scene);
86         return true;
87 }
88
89 static Mat4 aiMatrix2Mat(aiMatrix4x4 t)
90 {
91         return Mat4(t.a1, t.a2, t.a3, t.a4,
92                     t.b1, t.b2, t.b3, t.b4,
93                     t.c1, t.c2, t.c3, t.c4,
94                     t.d1, t.d2, t.d3, t.d4);
95 }
96
97 static void create_object(aiNode *node, Mat4 parent_transform, Scene *scene, const aiScene *ascene)
98 {
99         /* Note:
100            The 99% of the scenes have 1 mesh per node => for simplicity we only check the 1st one.
101            Also: the 3D models we are going to use for this demo, have flat structure (no hierarchy)
102            but just in case we need to replace them later, we calculate the transform by assuming that we
103            have a node hierarchy. This => that each object's modelling transformation is the
104            product of its local transformation (mTransformation) with the acc parent nodes transformations
105            (parent_transform)
106         */
107         Mat4 modelling_transform = parent_transform * aiMatrix2Mat(node->mTransformation);
108
109         if(node->mNumMeshes > 0) {
110                 Object *object = new Object;
111
112                 // get the mesh index from node
113                 int mesh_idx = node->mMeshes[0];
114                 object->mesh = scene->meshes[mesh_idx];
115
116                 // get the material index from the mesh that is assigned to this node
117                 aiMesh *amesh = ascene->mMeshes[mesh_idx];
118                 object->material = scene->materials[amesh->mMaterialIndex];
119
120                 // set the object's transformation
121                 object->transform = modelling_transform;
122                 scene->objects.push_back(object);
123         }
124
125         for(unsigned int i=0; i<node->mNumChildren; ++i) {
126                 create_object(node->mChildren[i], modelling_transform, scene, ascene);
127         }
128 }
129
130 static Mesh *load_mesh(const aiScene *scene, unsigned int index)
131 {
132         /* load mesh with index from scene using assimp */
133         aiMesh *amesh = scene->mMeshes[index];
134         if(!amesh) {
135                 fprintf(stderr, "Failed to load assimp mesh no: %d.\n", index);
136                 return 0;
137         }
138
139         Mesh *mesh;
140         if(use_vulkan) {
141                 mesh = new MeshVK;
142         }
143         else {
144                 mesh = new MeshGL;
145         }
146
147         mesh->name = std::string(amesh->mName.data);
148
149         for(unsigned int i=0; i<amesh->mNumVertices; ++i) {
150                 /* vertices */
151                 if(amesh->HasPositions()) {
152                         Vec3 vertex = Vec3(amesh->mVertices[i].x, amesh->mVertices[i].y,
153                                            amesh->mVertices[i].z);
154
155                         mesh->vertices.push_back(vertex);
156                 }
157                 else {
158                         fprintf(stderr, "Mesh has no geometry!\n");
159                         delete mesh;
160                         return 0;
161                 }
162
163                 /* normals */
164                 if(amesh->HasNormals()) {
165                         Vec3 normal = Vec3(amesh->mNormals[i].x, amesh->mNormals[i].y,
166                                            amesh->mNormals[i].z);
167                         mesh->normals.push_back(normal);
168                 }
169                 else {
170                         fprintf(stderr, "Mesh has no normals!\n");
171                         delete mesh;
172                         return 0;
173                 }
174
175                 /* texture coordinates */
176                 if(amesh->mTextureCoords[0]) {
177                         Vec2 tex_coord = Vec2(amesh->mTextureCoords[0][i].x, amesh->mTextureCoords[0][i].y);
178                         mesh->tex_coords.push_back(tex_coord);
179                 }
180                 else {
181                         mesh->tex_coords.push_back(Vec2(0, 0));
182                 }
183
184                 /* tangents */
185                 // if(amesh->mTangents) {
186                 //      mesh->which_mask |= MESH_TANGENT;
187                 //      Vec3 tangent = Vec3(amesh->mTangents[i].x, amesh->mTangents[i].y,
188                 //                          amesh->mTangents[i].z);
189                 //      mesh->tangents.push_back(tangent);
190                 // }
191                 // else {
192                 //      mesh->tangents.push_back(Vec3(1, 0, 0));
193                 // }
194         }
195         /* indices (called faces in assimp) */
196         if(amesh->HasFaces()) {
197                 for(unsigned int i=0; i<amesh->mNumFaces; ++i) {
198                         mesh->indices.push_back(amesh->mFaces[i].mIndices[0]);
199                         mesh->indices.push_back(amesh->mFaces[i].mIndices[1]);
200                         mesh->indices.push_back(amesh->mFaces[i].mIndices[2]);
201                 }
202         }
203         else
204                 fprintf(stderr, "No faces found.\n");
205
206         mesh->mat_idx = amesh->mMaterialIndex;
207         return mesh;
208 }
209
210 static Material *load_material(const aiScene *ascene, Scene *scene, unsigned int index)
211 {
212         aiMaterial *amat = ascene->mMaterials[index];
213         if(!amat) {
214                 fprintf(stderr, "Failed to load material no: %d.\n", index);
215                 return 0;
216         }
217
218         Material *mat = new Material;
219         mat->dtex = 0;
220         mat->shininess = 40;
221
222         aiString name;
223         amat->Get(AI_MATKEY_NAME, name);
224         mat->name = std::string(name.data);
225
226         aiColor4D color;
227         aiGetMaterialColor(amat, AI_MATKEY_COLOR_DIFFUSE, &color);
228         mat->diffuse = Vec3(color.r, color.g, color.b);
229
230         aiGetMaterialColor(amat, AI_MATKEY_COLOR_SPECULAR, &color);
231         float spstr;
232         aiGetMaterialFloat(amat, AI_MATKEY_SHININESS_STRENGTH, &spstr);
233         mat->specular = spstr * Vec3(color.r, color.g, color.b);
234
235         aiGetMaterialFloat(amat, AI_MATKEY_SHININESS, &mat->shininess);
236
237         aiString tex_name;
238         if(aiGetMaterialString(amat, AI_MATKEY_TEXTURE_DIFFUSE(0), &tex_name) == aiReturn_SUCCESS) {
239                 /* different scene objects might use the same texture, we shouldn't store it twice*/
240                 //mat->dtex = scene->find_texture(tex_name.data);
241                 if(!mat->dtex) {
242                         if(use_vulkan) {
243                                 mat->dtex = new TextureVK;
244                         }
245                         else {
246                                 mat->dtex = new TextureGL;
247                         }
248                         if(!mat->dtex->load(tex_name.data)) {
249                                 fprintf(stderr, "Failed to load texture data: %s.\n", tex_name.data);
250                                 delete mat->dtex;
251                                 mat->dtex = 0;
252                         }
253                         scene->textures.push_back(mat->dtex);
254                 }
255         }
256
257         return mat;
258 }